当父文档可能不存在时更新MongoDB子文档 [英] Update a MongoDB subdocument when the parent document might not exist

查看:96
本文介绍了当父文档可能不存在时更新MongoDB子文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的数据,由一个 books 集合和一个 books.reviews 子集合组成.

Here's my data, consisting of a books collection, with a books.reviews sub-collection.

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发送到服务器:

In Node.js (using Mongoose), I need for users to be able to submit reviews via a form, sending the review and the isbn of the book to the server, with the following conditions:

  1. 如果尚不存在带有特定isbn的图书,请添加该图书,然后添加评论(该图书显然尚不存在).
  2. 如果这本书确实存在...
    • 如果针对该用户的书 不存在该书的评论,则将其添加.
    • 如果该用户的本书确实存在该书的评论 ,请对其进行更新.
  1. If the book doesn't exist already with a specific isbn, add it, then add the review (it obviously doesn't already exist).
  2. If the book does exist...
    • If the review doesn't exist for this book for this user, add it.
    • If the review does exist for this book for this user, update it.

我可以使用4个独立的查询来执行此操作,但是我知道这不是最佳选择.我可以使用的最少查询数量是多少(当然,这些查询是什么)?

I can do this with 4 separate queries, but I know that's not optimal. What are the fewest number of queries I could use (and of course, what are those queries)?

推荐答案

您基本上有3种情况:

    书和评论都存在.这是一个简单的$set
  1. 这本书存在,但没有评论.这需要一个$push
  2. 这本书不存在.这需要{upsert:1}$setOnInsert
  1. both the book and the review exists. This is a simple $set
  2. the book exists but not the review. This need a $push
  3. the book does not exists. This need {upsert:1} and a $setOnInsert

在出现故障的情况下,我无法找到一种方法来统一这两种方法而不损害数据完整性(请记住,MongoDB没有原子事务).

I was not able to find a way to unify any two of these without compromising data integrity in case of failure (remember that MongoDB does not have atomic transaction).

因此,我的最好的主意如下:

So my best idea is the following:

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

您可能会盲目地原始运行这三个更新,因为它们之间没有重叠的情况.事情的妙处是所有这些操作都是幂等.因此,您可以一次或多次应用它们,并始终获得相同的结果.这在故障转移的情况下尤其重要.此外,万一发生故障,数据库也不会不一致或丢失现有数据.最糟糕的是,该评论被更新.最后,即使在并发更新的情况下,此也应保证数据的一致性(即:在这种情况下,一个更新将覆盖另一个更新,但是您不应该最终为同一本书拥有两个文档或获得两个评论)同一本书的同一用户的用户).
后面的一点必须确认,因为现在已经晚了,所以我的分析可能会有些疑问.

You may blindly run those three updates in a raw as there is no overlapping case between them. The beauty of the thing is all these operations are idempotent. So you can apply them once or several times and always get the same result. This is especially important in case of failover. In addition, there is no way for your DB to be inconsistent or to loose existing data in case of failure. At worst, the review is not updated. Finally this should guarantee data consistency even in case of concurrent updates (i.e.: in that case, one update will overwrite the other, but you shouldn't end up having two documents for the same book or two reviews of the same user for the same book).
That later point has to be confirmed as it is late here so my analysis might be somewhat doubtful.

最后一点,如果要减少MongoDB与应用程序之间的往返次数,可以查看

As final note, if you want to reduce the number of round-trips between MongoDB and your app, you might take a look at the update database command allowing you to wrap several updates in one command.

这篇关于当父文档可能不存在时更新MongoDB子文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆