MongoDB Atlas에서 데이터 쓰기 - 함수
이 페이지의 내용
개요
이 페이지의 예시에서는 Atlas 클러스터에서 데이터를 삽입, 업데이트 및 삭제하는 함수에서 MongoDB 쿼리 API를 사용하는 방법을 보여 줍니다.
참고
연합 데이터 소스는 쓰기 작업을 지원하지 않습니다.
데이터 모델
이 페이지의 예에서는 온라인 스토어에서 구매할 수 있는 다양한 품목을 모델링한 store.items
컬렉션을 사용합니다. 각 항목에는 name
, 재고 quantity
및 고객 reviews
의 배열이 있습니다.
{ "title": "Item", "required": ["_id", "name", "quantity", "reviews"], "properties": { "_id": { "bsonType": "objectId" }, "name": { "bsonType": "string" }, "quantity": { "bsonType": "int" }, "reviews": { "bsonType": "array", "items": { "bsonType": "object", "required": ["username", "comment"], "properties": { "username": { "bsonType": "string" }, "comment": { "bsonType": "string" } } } } } }
스니펫 설정
함수에서 코드 스니펫을 사용하려면 먼저 MongoDB 컬렉션 핸들을 인스턴스화해야 합니다:
exports = function() { const mongodb = context.services.get("mongodb-atlas"); const itemsCollection = mongodb.db("store").collection("items"); const purchasesCollection = mongodb.db("store").collection("purchases"); // ... paste snippet here ... }
Insert
삽입 작업은 하나 이상의 문서를 가져와서 MongoDB 컬렉션에 추가합니다.
작업 결과를 설명하는 문서를 반환합니다.
단일 문서 삽입(insertOne()
)
collection.insertOne()
메서드를 사용하여 단일 문서를 삽입할 수 있습니다.
다음 함수 스니펫은 단일 항목 문서를 items
컬렉션에 삽입합니다.
const newItem = { "name": "Plastic Bricks", "quantity": 10, "category": "toys", "reviews": [{ "username": "legolover", "comment": "These are awesome!" }] }; itemsCollection.insertOne(newItem) .then(result => console.log(`Successfully inserted item with _id: ${result.insertedId}`)) .catch(err => console.error(`Failed to insert item: ${err}`))
하나 이상의 문서 삽입(insertMany()
)
collection.insertMany()
메서드를 사용하면 여러 문서를 동시에 삽입할 수 있습니다.
다음 함수 스니펫은 여러 항목 문서를 items
컬렉션에 삽입합니다.
const doc1 = { "name": "basketball", "category": "sports", "quantity": 20, "reviews": [] }; const doc2 = { "name": "football", "category": "sports", "quantity": 30, "reviews": [] }; return itemsCollection.insertMany([doc1, doc2]) .then(result => { console.log(`Successfully inserted ${result.insertedIds.length} items!`); return result }) .catch(err => console.error(`Failed to insert documents: ${err}`))
Update
업데이트 작업은 MongoDB 컬렉션 에서 기존 문서를 찾아 데이터를 수정합니다. 표준 MongoDB 쿼리 구문을 사용하여 업데이트 할 문서를 지정하고 업데이트 연산자 를 사용하여 일치하는 문서에 적용 할 변경 사항을 설명합니다.
참고
Atlas App Services는 업데이트 작업을 실행하는 동안 문서에 예약된 필드(_id__baas_transaction
)를 임시로 추가합니다. App Services 외부에서 앱에서 사용하는 데이터를 수정하는 경우 이 필드의 설정을 해제해야 할 수 있습니다. 자세한 내용은 트랜잭션 잠금을 참조하세요.
단일 문서 업데이트(updateOne()
)
collection.updateOne()
메서드를 사용하여 단일 문서를 업데이트할 수 있습니다.
다음 함수 스니펫은 items
컬렉션에 있는 단일 문서의 name
을 lego
에서 blocks
로 업데이트하고 20.99
의 price
를 추가합니다:
const query = { "name": "lego" }; const update = { "$set": { "name": "blocks", "price": 20.99, "category": "toys" } }; const options = { "upsert": false }; itemsCollection.updateOne(query, update, options) .then(result => { const { matchedCount, modifiedCount } = result; if(matchedCount && modifiedCount) { console.log(`Successfully updated the item.`) } }) .catch(err => console.error(`Failed to update the item: ${err}`))
collection.findOneAndUpdate()
또는 collection.findOneAndReplace()
를 사용하여 단일 문서를 업데이트할 수도 있습니다. 두 메서드 모두 하나의 작업으로 업데이트된 문서를 찾고, 수정하고, 반환할 수 있습니다.
하나 이상의 문서 업데이트(updateMany()
)
collection.updateMany()
메서드를 사용하여 컬렉션에 있는 여러 문서를 업데이트할 수 있습니다.
다음 함수 스니펫은 items
컬렉션 내 모든 문서의 quantity
값에 10
을 곱하여 업데이트합니다:
const query = {}; const update = { "$mul": { "quantity": 10 } }; const options = { "upsert": false } return itemsCollection.updateMany(query, update, options) .then(result => { const { matchedCount, modifiedCount } = result; console.log(`Successfully matched ${matchedCount} and modified ${modifiedCount} items.`) return result }) .catch(err => console.error(`Failed to update items: ${err}`))
문서 업서트
업데이트 작업이 컬렉션의 문서와 일치하지 않는 경우 upsert
옵션을 true
로 설정하여 업데이트 쿼리와 일치하는 컬렉션에 새 문서 하나를 자동으로 삽입할 수 있습니다.
다음 함수 스니펫은 board game
의 name
이 있는 items
컬렉션 내 문서의 quantity
를 5
만큼 증가시켜 업데이트합니다. upsert
옵션이 활성화되어 있으므로 name
값이 "board game"
인 문서가 없으면 MongoDB는 name
필드가 "board
game"
(으)로 설정되고 quantity
값이 5
로 설정된 새 문서를 삽입합니다.
const query = { "name": "board games" }; const update = { "$inc": { "quantity": 5 } }; const options = { "upsert": true }; itemsCollection.updateOne(query, update, options) .then(result => { const { matchedCount, modifiedCount, upsertedId } = result; if(upsertedId) { console.log(`Document not found. Inserted a new document with _id: ${upsertedId}`) } else { console.log(`Successfully increased ${query.name} quantity by ${update.$inc.quantity}`) } }) .catch(err => console.error(`Failed to upsert document: ${err}`))
필드 업데이트 연산자
필드 연산자를 사용하면 문서의 필드와 값을 수정할 수 있습니다.
필드 값 설정
$set 연산자를 사용하면 문서의 다른 필드에 영향을 주지 않고 단일 필드의 값을 설정할 수 있습니다.
{ "$set": { "<Field Name>": <Value>, ... } }
필드 이름 바꾸기
$rename 연산자를 사용하여 문서에서 단일 필드의 이름을 변경할 수 있습니다.
{ "$rename": { "<Current Field Name>": <New Field Name>, ... } }
값 상향
$inc 연산자를 사용하여 필드의 현재 값에 지정된 숫자를 추가할 수 있습니다. 숫자는 양수 또는 음수일 수 있습니다.
{ "$inc": { "<Field Name>": <Increment Number>, ... } }
값 곱하기
$mul 연산자 를 사용하여 지정된 숫자와 필드 의 현재 값을 곱할 수 있습니다. 숫자는 양수 또는 음수일 수 있습니다.
{ "$mul": { "<Field Name>": <Multiple Number>, ... } }
배열 업데이트 연산자
배열 연산자를 사용하면 배열 내 값으로 작업할 수 있습니다.
요소를 배열로 밀어넣기
$push 연산자 를 사용하여 배열 필드 의 끝에 값을 추가할 수 있습니다.
{ "$push": { "<Array Field Name>": <New Array Element>, ... } }
배열에서 마지막 요소 제거
$pop 연산자를 사용하여 배열 필드의 첫 번째 또는 마지막 요소를 제거할 수 있습니다. 첫 번째 요소를 제거하려면 -1
을 지정하고 마지막 요소를 제거하려면 1
를 지정합니다.
{ "$pop": { "<Array Field Name>": <-1 | 1>, ... } }
배열에 고유 요소 추가
해당 값이 아직 배열 에 포함되어 있지 않은 경우 $addToSet 연산자 를 사용하여 배열 필드 에 값을 추가할 수 있습니다. 값이 이미 있는 경우 $addToSet
은 아무 작업도 수행하지 않습니다.
{ "$addToSet": { "<Array Field Name>": <Potentially Unique Value>, ... } }
배열에서 요소 제거
$pull 연산자 를 사용하여 배열 필드 에서 지정된 조건과 일치하는 값의 모든 인스턴스를 제거 할 수 있습니다.
{ "$pull": { "<Array Field Name>": <Value | Expression>, ... } }
배열의 모든 요소 업데이트
$[] (All Positional Update) 연산자를 사용하여 배열 필드의 모든 요소를 업데이트할 수 있습니다.
예시
학급의 개별 학생을 설명하는 students
컬렉션이 있다고 가정합니다. 각 문서에는 숫자 배열이 포함된 grades
필드가 포함되어 있습니다.
{ "_id" : 1, "grades" : [ 85, 82, 80 ] } { "_id" : 2, "grades" : [ 88, 90, 92 ] } { "_id" : 3, "grades" : [ 85, 100, 90 ] }
다음 업데이트 작업은 모든 학생의 grades
배열에 있는 모든 값에 10을 더합니다.
await students.updateMany( {}, { $inc: { "grades.$[]": 10 } }, )
업데이트 후 모든 성적 값이 10씩 증가했습니다.
{ "_id" : 1, "grades" : [ 95, 92, 90 ] } { "_id" : 2, "grades" : [ 98, 100, 102 ] } { "_id" : 3, "grades" : [ 95, 110, 100 ] }
배열의 특정 요소 업데이트
$[element] (Filtered Positional Update) 연산자를 사용하여 배열 필터를 기반으로 배열 필드의 특정 요소를 업데이트할 수 있습니다.
예시
학급의 개별 학생을 설명하는 students
컬렉션이 있다고 가정합니다. 각 문서에는 숫자 배열이 포함된 grades
필드가 포함되어 있으며, 이 중 일부는 100보다 큽니다.
{ "_id" : 1, "grades" : [ 15, 92, 90 ] } { "_id" : 2, "grades" : [ 18, 100, 102 ] } { "_id" : 3, "grades" : [ 15, 110, 100 ] }
다음 업데이트 작업은 100보다 큰 모든 성적 값을 정확히 100으로 설정합니다:
await students.updateMany( { }, { $set: { "grades.$[grade]" : 100 } }, { arrayFilters: [{ "grade": { $gt: 100 } }] } )
업데이트 후 100보다 큰 모든 성적 값은 정확히 100으로 설정되며 다른 모든 성적은 영향을 받지 않습니다.
{ "_id" : 1, "grades" : [ 15, 92, 90 ] } { "_id" : 2, "grades" : [ 18, 100, 100 ] } { "_id" : 3, "grades" : [ 15, 100, 100 ] }
삭제
삭제 작업은 MongoDB 컬렉션에서 기존 문서를 찾아서 제거합니다. 삭제할 문서를 지정하기 위해 표준 MongoDB 쿼리 구문을 사용합니다.
단일 문서 삭제(deleteOne()
)
collection.deleteOne()
메서드를 사용하여 컬렉션에서 단일 문서를 삭제할 수 있습니다.
다음 함수 스니펫은 items
컬렉션에서 name
값이 lego
인 문서 하나를 삭제합니다:
const query = { "name": "lego" }; itemsCollection.deleteOne(query) .then(result => console.log(`Deleted ${result.deletedCount} item.`)) .catch(err => console.error(`Delete failed with error: ${err}`))
또는 collection.findOneAndDelete()
를 사용하여 단일 문서를 업데이트할 수도 있습니다. 이 메서드를 사용하면 하나의 작업으로 삭제된 문서를 찾고, 제거하고, 반환할 수 있습니다.
하나 이상의 문서 삭제(deleteMany()
)
collection.deleteMany()
메서드를 사용하여 컬렉션에서 여러 항목을 삭제할 수 있습니다.
다음 스니펫은 items
컬렉션 내 reviews
가 없는 모든 문서를 삭제합니다.
const query = { "reviews": { "$size": 0 } }; itemsCollection.deleteMany(query) .then(result => console.log(`Deleted ${result.deletedCount} item(s).`)) .catch(err => console.error(`Delete failed with error: ${err}`))
일괄 쓰기
일괄 쓰기는 여러 쓰기 작업을 단일 작업으로 결합합니다. collection.bulkWrite()
메서드를 사용하여 일괄 쓰기 명령을 실행할 수 있습니다.
exports = async function(arg){ const doc1 = { "name": "velvet elvis", "quantity": 20, "reviews": [] }; const doc2 = { "name": "mock turtleneck", "quantity": 30, "reviews": [] }; var collection = context.services.get("mongodb-atlas") .db("store") .collection("purchases"); return await collection.bulkWrite( [{ insertOne: doc1}, { insertOne: doc2}], {ordered:true}); };
트랜잭션
MongoDB는 여러 문서를 단일 단위로 읽고 쓸 수 있는 다중 문서 트랜잭션을 지원하므로 컬렉션 전체에서 여러 문서를 읽고 쓸 수 있습니다.
트랜잭션을 수행하려면 다음을 따릅니다:
client.startSession()
을 사용하여 클라이언트 세션을 가져오고 시작합니다.session.withTransaction()
를 호출하여 트랜잭션 을 정의합니다. 이 메서드는 비동기 콜백 함수를 사용합니다.session.withTransaction(async () => { // ... Run MongoDB operations in this callback }) 트랜잭션 콜백 함수에서 트랜잭션에 포함하려는 MongoDB 쿼리를 실행합니다. 트랜잭션에 포함되도록 하려면 각 쿼리에
session
을 전달해야 합니다.await accounts.updateOne( { name: userSubtractPoints }, { $inc: { browniePoints: -1 * pointVolume } }, { session } ); 콜백에 오류가 발생하면
session.abortTransaction()
을 호출하여 트랜잭션을 중지합니다. 중단된 트랜잭션은 어떤 데이터도 수정하지 않습니다.try { // ... } catch (err) { await session.abortTransaction(); } 트랜잭션이 완료되면
session.endSession()
을 호출하여 세션을 종료하고 리소스를 확보합니다.try { // ... } finally { await session.endSession(); }
다음 예시 에서는 'henry'와 'michelle'이라는 두 사용자를 생성하고 트랜잭션 을 사용하여 해당 사용자 간에 'browniePoints'를 원자적으로 이동합니다.
exports = function () { const client = context.services.get("mongodb-atlas"); const db = client.db("exampleDatabase"); const accounts = db.collection("accounts"); const browniePointsTrades = db.collection("browniePointsTrades"); // create user accounts with initial balances accounts.insertOne({ name: "henry", browniePoints: 42 }); accounts.insertOne({ name: "michelle", browniePoints: 144 }); // trade points between user accounts in a transaction tradeBrowniePoints( client, accounts, browniePointsTrades, "michelle", "henry", 5 ); return "Successfully traded brownie points."; }; async function tradeBrowniePoints( client, accounts, browniePointsTrades, userAddPoints, userSubtractPoints, pointVolume ) { // Step 1: Start a Client Session const session = client.startSession(); // Step 2: Use withTransaction to start a transaction, execute the callback, and commit (or abort on error) // Note: The callback for withTransaction MUST be async and/or return a Promise. try { await session.withTransaction(async () => { // Step 3: Execute the queries you would like to include in one atomic transaction // Important:: You must pass the session to the operations await accounts.updateOne( { name: userSubtractPoints }, { $inc: { browniePoints: -1 * pointVolume } }, { session } ); await accounts.updateOne( { name: userAddPoints }, { $inc: { browniePoints: pointVolume } }, { session } ); await browniePointsTrades.insertOne( { userAddPoints: userAddPoints, userSubtractPoints: userSubtractPoints, pointVolume: pointVolume, }, { session } ); }); } catch (err) { // Step 4: Handle errors with a transaction abort await session.abortTransaction(); } finally { // Step 5: End the session when you complete the transaction await session.endSession(); } }