嵌入式文档中的批量更新

普拉蒂克·博特拉

将条目添加到每日密钥时,有两种情况需要处理

a)添加新的一天-:{“ day”:6,“ sessions”:300}

b)更新特定日期的字段,例如是否重新计算了会话并将第二天更改为105

样本架构

{
    _id: "201010/site-1/apache_pb.gif",
    metadata: {
        date: ISODate("2000-10-00T00:00:00Z"),
        site: "site-1",
        page: "/apache_pb.gif" },
    daily: [
        { "day": 1, "sessions": 300, "bounces": 10},
        { "day": 2, "sessions": 100, "bounces": 5},
        { "day": 3, "sessions": 10},
        { "day": 4, "sessions": 100, "bounces": 4}
    ]
}

我最初尝试过

db.monthly.update(
    { "metadata.page": "/apache_pb.gif", "daily.day": "6" },
    { "$set": { "daily.$.sessions": 300 } },
    { "upsert": true }
)

但是如果不存在这一天,我会收到“位置运算符未从查询中找到所需的匹配项”

我可以看到操作正在发生的唯一方法是

db.monthly.update(
    { "metadata.page": "/apache_pb.gif", "daily.day": "6" },
    { "$set": { "daily.$.sessions": 300 } }
)

在响应中,如果我被修改为0,则执行此操作

db.monthly.update(
    { "metadata.page": "/apache_pb.gif" },
    { "$push": { "daily": {
        "day": "6",
        "sessions": 300
    }}
)

这似乎一点也不优雅。知道我们是否可以使用单个查询来做到这一点吗?(也许是BulkOperations)

布雷克七世

就像您的标题所暗示的那样,解决方案是使用Bulk Operations API,该API可用于在单个请求中以单个响应发送多个操作:

var bulk = db.monthly.initializeOrderedBulkOp();

// Attempt to match and modify
bulk.find({ "metadata.page": "/apache_pb.gif", "daily.day": 6 }).updateOne({
    "$inc": { "daily.$.sessions": 600 }
});

// Attempt to push where matched and array element does not exist
bulk.find({ "metadata.page": "/apache_pb.gif", "daily.day": { "$ne": 6 } }).updateOne({
    "$push": { "daily": { "day": 6, "sessions": 600 } }
});

// upsert and only modify on actual creation
bulk.find({ "metadata.page": "/apache_pb.gif" }).upsert().updateOne({
    "$setOnInsert": {
        "_id": "201010/site-1/apache_pb.gif",
        "metadata": {
            "date": ISODate("2000-10-00T00:00:00Z"),
            "site": "site-1",
            "page": "/apache_pb.gif" 
        },
        "daily": [
            { "day": 6, "sessions": 600 }
        ]
    }
});

// The only time the server is actually touched.
bulk.execute();

因此,尽管有三种操作来处理批处理中的所有情况,但只有对服务器的每个请求和一个响应。还要注意,只有组操作中的一个实际上可以修改或创建一些数据。

基本情况是匹配和修改所需元素的位置。如果满足条件,则更新数组元素。在此示例中,“递增”是因为前面提到了预聚合的数据,因此在这种情况下,通常增加已经存在的值是有意义的。

下一步是测试数组成员不存在的位置,然后测试$push将新元素放入数组中。

最后,有一个“ upsert”条件,在前面的陈述中故意不存在。故意不查看数组元素,而只是查看文档的唯一属性。只有在不满足该查询条件的情况下,才考虑“ upsert”是安全的,因为在将意图添加到数组时,在检查中添加数组元素可能会创建一个新文档。

$setOnInsert此处修饰符可确保不会对实际找到的任何文档进行任何更改,并且唯一发生的操作是实际发生“ upsert”时。

因此,控制数组的添加并同时考虑“ upsert”行为需要这些基本步骤。但是,“批量操作”的使用使它成为对服务器的单个请求/响应,以及确保只有一个操作有效的通用逻辑。

它非常高效,并且消除了在请求和响应中与服务器来回通信之前执行这些操作中的每一个操作的开销,直到其中一项操作成功为止。

此控件无法进行一次查询/更新。但是一个请求是可能的,这就是它的作用。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章