MongoDB增量或Upsert

时间:2015-07-05 14:56:17

标签: mongodb

鉴于以下文件结构:

{
         '_id': ObjectId("559943fcda2485a66285576e"),
         'user': '70gw3',
         'data': [
            {
              'date': ISODate("2015-06-29T00:00:00.0Z"),
              'clicks': 1,
            },
            {
              'date': ISODate("2015-06-30T00:00:00.0Z"),
              'clicks': 5,
            },
          ]
    }

我如何增加clicks的{​​{1}}值,如果它不存在则会增加[整个文档特定日期],使其等于到2015-06-30

2 个答案:

答案 0 :(得分:2)

不幸的是,无法在单个查询中实现您的目标。但相反,你可以做以下

var exists = db.yourCollection.find(
    {'_id': ObjectId("559943fcda2485a66285576e"), 'data.date': <your date>}
).count()

此查询将返回具有指定_id的文档数和具有data数组中指定日期的对象。由于_id字段是唯一的,因此您最多只能得到一个结果。如果data数组中不存在此元素,则不会得到任何结果。因此,您有以下情况:

  • exists == 1: IS 具有指定日期的元素
  • exists == 0:具有指定日期的 IS NO 元素

然后这可能成为你的条件:

if (exists) {
    db.yourCollection.update({_id: <your id>, 'data.date': <your date>}, {$inc: {'data.$.clicks': 1}})
} else {
    if (db.runCommand({findAndModify: 'yourCollection', query: {_id: <your id>, 'data.date': {$ne: <your date>}}, update: {$push: {data: {date: <your date>, clicks: 1}}}}).value) {
         db.yourCollection.update({_id: <your id>, 'data.date': <your date>}, {$inc: {'data.$.clicks': 1}})
    }
}

答案 1 :(得分:1)

正确的答案是,虽然您需要执行两个更新操作才能实现逻辑,但无需以某种方式查找和检查数据。

您有两个基本条件

  1. 如果元素在那里然后更新它
  2. 如果元素,则添加
  3. 这个过程基本上是两次更新。一个会成功,另一个则不会。无需检查。

    实现此功能的最佳方法可能是使用"Bulk"操作API。这允许将两个更新语句同时发送到服务器,并且响应它是单个响应,因此行程较少。但即使你不使用它,逻辑也是一样的。

    var bulk = db.collection.initializeOrderedBulkOp();
    
    // Update the date where it matched
    bulk.find({ "user": "70gw3", "data.date": new Date("2015-06-30") })
        .updateOne({ "$inc": { "data.$.clicks": 1 } });
    
    // Push a new element where date does not match
    bulk.find({ "user": "70gw3", "data.date": { "$ne": new Date("2015-06-30") } })
        .updateOne({ "$push": { "data": { "date": new Date("2015-06-30"), "clicks": 1 } }});
    
    bulk.execute();
    

    简而言之,在为任何文档发送的两个更新请求中,只有一个操作实际上会修改任何内容。这是因为测试“日期”的条件是彼此的“反向”,因为你“更新”当前存在,并且“创建”匹配元素不存在。

    两个状态不能同时存在,只要“创建”跟随“更新”逻辑就是声音。所以首先尝试更新,然后尝试“创建”,找不到匹配项。