MongoDB Atlas でデータを書込み (write) - 関数
項目一覧
Overview
このページの例は、関数で MongoDB Query API を使用して Atlas クラスターにデータを挿入、アップデート、削除する方法を示しています。
注意
フェデレーティッド データソースは書込み操作をサポートしていません。
データモデル
このページの例では、オンライン ストアで購入可能なさまざまなアイテムをモデル化した 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
挿入操作は、1 つ以上のドキュメントを受け取り、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}`))
1 つ以上のドキュメントを挿入(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()
を使用して単一のドキュメントを更新することもできます。 どちらの方法でも、1 回の操作で更新されたドキュメントを検索、変更、および返すことができます。
1 つ以上のドキュメントを更新(updateMany()
)
collection.updateMany()
メソッドを使用して、コレクション内の複数のドキュメントを更新できます。
次の関数スニペットは、 quantity
値に10
を乗算して、 items
コレクション内のすべてのドキュメントを更新します。
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
に設定することで、アップデート クエリに一致する新しいドキュメントを 1 つ自動的に挿入できます。
次の関数スニペットは、 quantity
を5
ずつ増加させて、 name
がboard game
のitems
コレクション内のドキュメントを更新します。 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演算子を使用すると、ドキュメント内の他のフィールドに影響を与えずに 1 つのフィールドの値を設定できます。
{ "$set": { "<Field Name>": <Value>, ... } }
フィールド名の変更
$rename演算子を使用して、ドキュメント内の 1 つのフィールドの名前を変更できます。
{ "$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>, ... } }
配列内のすべての要素のアップデート
$[](すべての位置更新)演算子を使用して、配列フィールド内のすべての要素を更新できます。
例
クラス内の個々の生徒を説明する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](フィルタリング位置更新)演算子を使用して、配列フィルターに基づいて配列フィールド内の特定の要素を更新できます。
例
クラス内の個々の生徒を説明する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
であるドキュメントを 1 つ削除します。
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()
を使用して単一のドキュメントを更新することもできます。 このメソッドを使用すると、1 回の操作で削除されたドキュメントを検索、削除、および返すことができます。
1 つ以上のドキュメントを削除しました(deleteMany()
)
collection.deleteMany()
メソッドを使用して、コレクションから複数の項目を削除できます。
次のスニペットは、 reviews
を持たないitems
コレクション内のすべてのドキュメントを削除します。
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}`))
一括書込み (write)
一括書込みは、複数の書込み操作を 1 つの操作に結合します。 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(); }
次の例では、"enry" と "milkshell" の 2 人のユーザーを作成し、トランザクションを使用してこれらのユーザー間で "brewiePoints" を不可分的に移動します。
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(); } }