Docs Menu
Docs Home
/ /
Atlas App Services
/ /

MongoDB Atlas でデータを書込み (write) - 関数

項目一覧

  • Overview
  • データモデル
  • スニペットのセットアップ
  • Insert
  • 単一ドキュメントを挿入( insertOne()
  • 1 つ以上のドキュメントを挿入( insertMany()
  • Update
  • 単一ドキュメントを更新( updateOne()
  • 1 つ以上のドキュメントを更新( updateMany()
  • ドキュメントをアップサートする
  • フィールド 更新演算子
  • 配列更新演算子
  • 削除
  • 単一ドキュメントの削除( deleteOne()
  • 1 つ以上のドキュメントを削除しました( deleteMany()
  • 一括書込み (write)
  • トランザクション

このページの例は、関数で MongoDB Query API を使用して Atlas クラスターにデータを挿入、アップデート、削除する方法を示しています。

注意

フェデレーティッド データソースは書込み操作をサポートしていません。

このページの例では、オンライン ストアで購入可能なさまざまなアイテムをモデル化した store.itemsという名前のコレクションを使用します。 各アイテムにはname 、在庫quantity 、カスタマーの配列reviewsがあります。

Store.item の 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 ...
}

挿入操作は、1 つ以上のドキュメントを受け取り、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()を使用して単一のドキュメントを更新することもできます。 どちらの方法でも、1 回の操作で更新されたドキュメントを検索、変更、および返すことができます。

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 つ自動的に挿入できます。

次の関数スニペットは、 quantity5ずつ増加させて、 nameboard gameitemsコレクション内のドキュメントを更新します。 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 クエリ構文を使用して、削除するドキュメントを指定します。

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 回の操作で削除されたドキュメントを検索、削除、および返すことができます。

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

一括書込みは、複数の書込み操作を 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 は、コレクション間でも、複数のドキュメントをアトミックに読み書きできるマルチドキュメントトランザクションをサポートしています。

トランザクションを実行するには、以下を使用します。

  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();
    }

次の例では、"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();
}
}

戻る

読み取り