并行更新MongoDB中嵌入式文档的数组元素 [英] Concurrent update of array elements which are embedded documents in MongoDB

查看:72
本文介绍了并行更新MongoDB中嵌入式文档的数组元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在MongoDB的x集合中有这样的文档:

I have documents like this one at collection x at MongoDB:

{
    "_id" : ...
    "attrs" : [
        {
            "key": "A1",
            "type" : "T1",
            "value" : "13"
        },
        {
            "key": "A2",
            "type" : "T2",
            "value" : "14"
        }
    ]
}

上面的A1A2元素只是示例:attrs字段可以容纳任意数量的数组元素.

The A1 and A2 elements above are just examples: the attrs field may hold any number of array elements.

我需要从访问MongoDB的几个独立客户端同时访问attrs阵列.例如,考虑两个客户端,一个客户端想要将等于"A1"的key标识的元素的value更改为"80",另一个想要等于到"A2"到"20".使用MongoDB操作是否有任何紧凑的方法?

I'd need to access concurrently to the attrs array from several independent clients accessing to MongoDB. For example, considers two clients, one wanting to change the value of the element identified by key equal to "A1" to "80" and other wanting to change the value of the element identified by key equal to "A2" to "20". Is there any compact way of doing it using MongoDB operations?

重要的是要注意:

  • 客户不知道每个元素在attr数组中的位置,只知道必须修改其值的元素的键.
  • 读取客户空间中的整个attrs数组,在客户空间中搜索要修改的元素,然后使用新数组(其中要修改的元素已更改)更新attrs会涉及竞争条件.
  • 客户还可以添加和删除数组中的元素.因此,首先在MongoDB上进行搜索以找到要修改的元素的位置,然后使用该特定位置对其进行更新通常是行不通的,因为可以添加/删除元素,从而改变先前找到的位置.
  • Clients doesn't know the position of each element in the attr array, only the key of the element which value has to be modified.
  • Reading the whole attrs array in client space, searching the element to modify at client space, then updating attrs with the new array (in which the element to modify has been changed) would involve race conditions.
  • Clients also may add and remove elements in the array. Thus, doing a first search at MongoDB to locate the position of the element to modify, then update it using that particular position doesn't work in general, as elements could have been added/removed thus altering of the position previously found.

推荐答案

这里的过程确实非常简单,只在您要查找或创建"数组中元素的位置上有所不同.

The process here is really quite simple, it only varies in where you want to "find or create" the elements in the array.

首先,假设每个键的元素已经到位,那么简单的情况是查询该元素并使用通过

First, assuming the elements for each key are in place already, then the simple case is to query for the element and update with the index returned via the positional $ operator:

db.collection.update(
   {
       "_id": docId, 
       "attrs": { "$elemMatch": { "key": "A1", "type": "T1" } }
   }
   { "$set": { "attrs.$.value": "20" }
)

这只会修改匹配的元素,而不会影响其他元素.

That will only modify the element that is matched without affecting others.

在第二种情况下,需要查找或创建"并且特定的键可能不存在,则可以使用两个"更新语句.但是批量操作API 允许您在单个请求中具有单个响应的服务器:

In the second case where "find or create" is required and the particular key may not exist, then you use "two" update statements. But the Bulk Operations API allows you to do this in a single request to the server with a single response:

var bulk = db.collection.initializeOrderedBulkOp();

// Try to update where exists
bulk.find({
    "_id": docId,
    "attrs": { "$elemMatch": { "key": "A1", "type": "T2" } }
}).updateOne({
    "$set": { "attrs.$.value": "30" }
});

// Try to add where does noes not exist
bulk.find({
    "_id": docId,
    "attrs": { "$not": { "$elemMatch": { "key": "A1", "type": "T2" } } }
}).updateOne({
    "$push": { "attrs": { "key": "A1", "type": "T2", "value": "30" } }
});

bulk.execute();

基本逻辑是,像以前一样,首先尝试进行更新以使元素与所需值匹配.其他条件通过使用 $not .

The basic logic being that first the update attempt is made to match an element with the required values just as done before. The other condition tests for where the element is not found at all by reversing the match logic with $not.

在未找到数组元素的情况下,则可以通过 $push .

In the case where the array element was not found then a new one is valid for addition via $push.

我真的应该补充一点,因为我们在这里专门寻找否定匹配,所以始终建议您通过一些唯一的标识符(例如_id键)来匹配要更新的文档".尽管可以使用多个"更新,但是您需要小心自己在做什么.

I should really add that since we are specifically looking for negative matches here it is always a good idea to match the "document" that you intend to update by some unique identifier such as the _id key. While possible with "multi" updates, you need to be careful about what you are doing.

因此,在运行查找或创建"过程的情况下,会将不匹配的元素正确地添加到数组中,而不会干扰其他元素,并且以相同的方式应用针对预期匹配的先前更新:

So in the case of running the "find or create" process then element that was not matched is added to the array correctly, without interferring with other elements, also the previous update for an expected match is applied in the same way:

{
    "_id" : ObjectId("55b570f339db998cde23369d"),
    "attrs" : [
            {
                    "key" : "A1",
                    "type" : "T1",
                    "value" : "20"
            },
            {
                    "key" : "A2",
                    "type" : "T2",
                    "value" : "14"
            },
            {
                    "key" : "A1",
                    "type" : "T2",
                    "value" : "30"
            }
    ]
}

这是一个简单的模式,当然,这里的批量操作消除了与服务器之间发送和接收多个请求所涉及的所有开销.所有这些令人愉快地工作,而不会干扰可能存在或不存在的其他元素.

This is a simple pattern to follow, and of course the Bulk Operations here remove any overhead involved by sending and receiving multiple requests to and from the server. All of this hapily works without interferring with other elements that may or may not exist.

除此之外,标准操作员还支持将数据保留在数组中以方便查询和分析,而无需为了遍历元素而转换为JavaScript服务器处理,还有其他好处.

Aside from that, there are the extra benefits of keeping the data in an array for easy query and analysis as supported by the standard operators without the need to revert to JavaScript server processing in order to traverse the elements.

这篇关于并行更新MongoDB中嵌入式文档的数组元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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