Docs 菜单

Docs 主页Atlas App Services

在 MongoDB Atlas 中写入数据 — 函数

在此页面上

  • 概述
  • 数据模型
  • 片段设置
  • 插入
  • 插入单个文档 (insertOne())
  • 插入一个或多个文档 (insertMany())
  • 更新(Update)
  • 更新单个文档 (updateOne())
  • 更新一个或多个文档 (updateMany())
  • 更新或插入文档
  • 字段更新运算符
  • 数组更新运算符
  • 删除
  • 删除单个文档 (deleteOne())
  • 删除一个或多个文档 (deleteMany())
  • 批量写入
  • 事务

本页上的示例演示了如何在函数中使用 MongoDB 查询 API 在 Atlas 集群中插入、更新和删除数据。

注意

联合数据源不支持写入操作

本页上的示例使用一个名为 store.items 的集合,它对在线商店中可购买的各种商品进行建模。每件商品具有 name、库存 quantity和客户 reviews 数组。

store.items 的 JSON 模式
{
"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() 方法更新集合中的多个文档。

以下函数片段将 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,自动将单个新文档插入到与更新查询匹配的集合。

以下函数片段将 quantity 增加 5,以更新 items 集合中 nameboard game 的文档。已启用 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>, ... } }

您可以使用$[](所有位置更新)操作符更新数组字段中的所有元素:

例子

请考虑一个描述班级中的各个学生的 students 集合。每个文档都包含一个 grades 字段,其中包含一个数字数组:

{ "_id" : 1, "grades" : [ 85, 82, 80 ] }
{ "_id" : 2, "grades" : [ 88, 90, 92 ] }
{ "_id" : 3, "grades" : [ 85, 100, 90 ] }

以下更新操作将 10 添加到每个学生的 grades 数组中的所有值:

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 的文档:

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
    }, {
    readPreference: "primary",
    readConcern: { level: "local" },
    writeConcern: { w: "majority" },
    })
  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");
db = client.db("exampleDatabase");
accounts = db.collection("accounts");
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: Optional. Define options to use for the transaction
const transactionOptions = {
readPreference: "primary",
readConcern: { level: "local" },
writeConcern: { w: "majority" },
};
// Step 3: 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 4: 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 }
);
}, transactionOptions);
} catch (err) {
// Step 5: Handle errors with a transaction abort
await session.abortTransaction();
} finally {
// Step 6: End the session when you complete the transaction
await session.endSession();
}
}
← 从 MongoDB Atlas 中读取数据 — 函数