Docs Menu
Docs Home
/ /
Atlas App Services
/ /

MongoDB Atlas에서 데이터 쓰기 - 함수

이 페이지의 내용

  • 개요
  • 데이터 모델
  • 스니펫 설정
  • Insert
  • 단일 문서 삽입(insertOne())
  • 하나 이상의 문서 삽입(insertMany())
  • Update
  • 단일 문서 업데이트(updateOne())
  • 하나 이상의 문서 업데이트(updateMany())
  • 문서 업서트
  • 필드 업데이트 연산자
  • 배열 업데이트 연산자
  • 삭제
  • 단일 문서 삭제(deleteOne())
  • 하나 이상의 문서 삭제(deleteMany())
  • 일괄 쓰기
  • 트랜잭션

이 페이지의 예시에서는 Atlas 클러스터에서 데이터를 삽입, 업데이트 및 삭제하는 함수에서 MongoDB 쿼리 API를 사용하는 방법을 보여 줍니다.

참고

이 페이지의 예에서는 온라인 스토어에서 구매할 수 있는 다양한 품목을 모델링한 store.items 컬렉션을 사용합니다. 각 항목에는 name, 재고 quantity 및 고객 reviews의 배열이 있습니다.

store.items의 JSON schema
{
"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 ...
}

삽입 작업은 하나 이상의 문서를 가져와서 MongoDB 컬렉션에 추가합니다.

작업 결과를 설명하는 문서를 반환합니다.

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}`))

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}`))

업데이트 작업은 MongoDB 컬렉션 에서 기존 문서를 찾아 데이터를 수정합니다. 표준 MongoDB 쿼리 구문을 사용하여 업데이트 할 문서를 지정하고 업데이트 연산자 를 사용하여 일치하는 문서에 적용 할 변경 사항을 설명합니다.

참고

Atlas App Services는 업데이트 작업을 실행하는 동안 문서에 예약된 필드(_id__baas_transaction)를 임시로 추가합니다. App Services 외부에서 앱에서 사용하는 데이터를 수정하는 경우 이 필드의 설정을 해제해야 할 수 있습니다. 자세한 내용은 트랜잭션 잠금을 참조하세요.

collection.updateOne() 메서드를 사용하여 단일 문서를 업데이트할 수 있습니다.

다음 함수 스니펫은 items 컬렉션에 있는 단일 문서의 namelego에서 blocks로 업데이트하고 20.99price를 추가합니다:

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()를 사용하여 단일 문서를 업데이트할 수도 있습니다. 두 메서드 모두 하나의 작업으로 업데이트된 문서를 찾고, 수정하고, 반환할 수 있습니다.

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 gamename이 있는 items 컬렉션 내 문서의 quantity5만큼 증가시켜 업데이트합니다. 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 쿼리 구문을 사용합니다.

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()를 사용하여 단일 문서를 업데이트할 수도 있습니다. 이 메서드를 사용하면 하나의 작업으로 삭제된 문서를 찾고, 제거하고, 반환할 수 있습니다.

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는 여러 문서를 단일 단위로 읽고 쓸 수 있는 다중 문서 트랜잭션을 지원하므로 컬렉션 전체에서 여러 문서를 읽고 쓸 수 있습니다.

트랜잭션을 수행하려면 다음을 따릅니다:

  1. client.startSession()을 사용하여 클라이언트 세션을 가져오고 시작합니다.

  2. session.withTransaction() 를 호출하여 트랜잭션 을 정의합니다. 이 메서드는 비동기 콜백 함수를 사용합니다.

    session.withTransaction(async () => {
    // ... Run MongoDB operations in this callback
    })
  3. 트랜잭션 콜백 함수에서 트랜잭션에 포함하려는 MongoDB 쿼리를 실행합니다. 트랜잭션에 포함되도록 하려면 각 쿼리에 session을 전달해야 합니다.

    await accounts.updateOne(
    { name: userSubtractPoints },
    { $inc: { browniePoints: -1 * pointVolume } },
    { session }
    );
  4. 콜백에 오류가 발생하면 session.abortTransaction()을 호출하여 트랜잭션을 중지합니다. 중단된 트랜잭션은 어떤 데이터도 수정하지 않습니다.

    try {
    // ...
    } catch (err) {
    await session.abortTransaction();
    }
  5. 트랜잭션이 완료되면 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();
}
}

돌아가기

읽기