以下是我的数据,包含 books 集合,以及 books.reviews 子集合。
books = [{
_id: ObjectId("5558f40ad498c653748cf045"),
title: "Widget XYZ",
isbn: 1234567890,
reviews: [
{
_id: ObjectId("5558f40ad498c653748cf046"),
userId: "01234",
rating: 5,
review: "Yay, this great!"
},
{
_id: ObjectId("5558f40ad498c653748cf047"),
userId: "56789",
rating: 3,
review: "Meh, this okay."
}
]
}]
在Node.js中(使用Mongoose),我需要用户能够通过表单提交评论,将评论和书籍的isbn发送到服务器,具有以下条件:
我可以通过4个单独的查询来完成此操作,但我知道这不是最佳的。我可以使用的查询数量最少(当然,这些查询是什么)?
答案 0 :(得分:4)
你基本上有3个案例:
$set
$push
{upsert:1}
和$setOnInsert
在发生故障的情况下,我无法在不损害数据完整性的情况下找到统一其中任何两个的方法(请记住,MongoDB没有原子事务)。
所以我的最好的想法如下:
// Case 1:
db.books.update({isbn:'1234567890',
review: { $elemMatch: {userID: '01234'}}},
{$set: {'review.$.rating': NEW_RATING}}
)
// Case 2:
db.books.update({isbn:'1234567890',
review: { $not: { $elemMatch: {userID: '01234'}}}},
{$push: {review: {rating: NEW_RATING, userID:'01234'}}}
)
// Case 3:
db.books.update({isbn:'1234567890'},
{$setOnInsert: {review: [{rating: NEW_RATING, userID:'01234'}]}},
{upsert:1}
)
您可能会盲目地在原始版本中运行这三个更新,因为它们之间没有重叠的情况。所有这些操作都是idempotent。因此,您可以应用它们一次或多次,并始终获得相同的结果。这在故障转移的情况下尤其重要。此外,如果出现故障,您的数据库无法保持不一致或无法释放现有数据。在最坏的情况下,审核不更新。最后这个应该保证数据的一致性,即使在并发更新的情况下(例如:在这种情况下,一个更新将覆盖另一个,但你最终不应该有两本文件用于同一本书或两篇评论同一本书的同一用户)。
后面的一点必须得到证实,因为它已经很晚了,所以我的分析可能有点令人怀疑。
最后需要注意的是,如果你想减少MongoDB和你的应用程序之间的往返次数,你可以看一下update
database command,允许你在一个命令中包含多个更新。