在插入嵌入文档MONGODB时递增计数器



我的文档结构类似于这个

{
    "_id" : {
        "Owner" : 651668690,
        "WeekOfTheYear" : 2
    },
    "calldetails" : {
        "426743784" : {
           "TotalDuration" : 204,
            "count" : 4
        },
        "752982293" : {
            "TotalDuration" : 206,
            "count" : 6
        }
    },
    "totalDuration" : 410,
    "totalcalls" : 10,
    "totaluniquecallers" : 0
}

只有在calldetails中创建了新的子文档时,我才想增加totaluniquecallers字段。我使用的是mongodb java驱动程序,并启用了upstart。

我的查询是这个

    BasicDBObject Query = new BasicDBObject();
    Query.put("_id.Owner", id);
    Query.put("_id.WeekOfTheYear", week);
    //update
    BasicDBObject update = new BasicDBObject();
    BasicDBObject incrementFields = new BasicDBObject();
    incrementFields.put("totalDuration", logdetails.getInt("duration"));
    incrementFields.put("totalcalls",1);
     incrementFields.put("calldetails."+logdetails.get("Phonenumber")+".TotalDuration",logdetails.getInt("duration"));
    incrementFields.put("calldetails."+logdetails.get("Phonenumber")+".count",1);
    update.put("$inc", incrementFields);
    WriteResult result1 = collection3.update(Query, update, true, false);

我试过$addToSet或$set,但里面似乎不允许增量。因此,在这个用例中,我基本上需要一个文档中的子文档数或"calldetails"字段中的总文档数,任何人都可以帮助我吗;

请注意:我正在尝试进行预隔离,因此每次插入新唱片时我都会更新。因此,每次在"calldetails"文档中创建新条目时,我都需要增加"totaluniquecallers"字段

问题


这里的整体逻辑有几个问题,所以让我们试着解决它们:

一个是您的子文档实际上不是数组,这就是像$addToSet这样的运算符在您身上失败的原因。实际上,这对你来说是件好事,所以你应该改变你的模式:

{
    "_id" : {
        "Owner" : 651668690,
        "WeekOfTheYear" : 2
    },
    "calldetails" : [
       { 
           "number": "426743784",
           "TotalDuration" : 204,
            "count" : 4
       },
       {
           "number": "752982293",
            "TotalDuration" : 206,
            "count" : 6
       }
    ],
    "totalDuration" : 410,
    "totalcalls" : 10,
    "totaluniquecallers" : 0
}

其次,$addToSet在这里总是会失败,因为"集合"实际上是什么

db.collection.update(
    {
        "_id" : {
            "Owner" : 651668690,
            "WeekOfTheYear" : 2
        }
    },
    {
        "$addToSet": { 
            "number": "426743784",
            "TotalDuration" : 204,
             "count" : 0
        }
    }
)

结果自然是这样的:

{
    "_id" : {
        "Owner" : 651668690,
        "WeekOfTheYear" : 2
    },
    "calldetails" : [
       { 
           "number": "426743784",
           "TotalDuration" : 204,
            "count" : 4
       },
       { 
           "number": "426743784",
           "TotalDuration" : 204,
            "count" : 0
       },
       {
           "number": "752982293",
            "TotalDuration" : 206,
            "count" : 6
       }
    ],
    "totalDuration" : 410,
    "totalcalls" : 10,
    "totaluniquecallers" : 0
}

因此,由于新的"集合成员"实际上与已经存在的成员不同,您将获得另一个条目。因此$addToSet不是这里的答案。

重新设计


从本质上讲,这不是一个真正适合嵌入式文档的模式设计。你真正想要的是:

{
    "Owner" : 651668690,
    "time": ISODate("2014-04-18T10:44:22.366Z")
    "number": "426743784",
    "duration" : 60,
},
{
    "Owner" : 651668690,
    "time" : ISODate("2014-04-18T10:50:22.366Z")
    "number": "752982293",
    "duration" : 100,
},
{
    "Owner" : 651668690,
    "time": ISODate("2014-04-18T11:44:22.366Z")
    "number": "426743784",
    "duration" : 60,
},

为什么?现在让我们考虑您的需求:

  1. 所有插入都是原子的。这意味着你只需每次写一次就可以将新的细节添加到集合中。因此,每一次"通话"都只是简单地记录了其中的细节。不需要"addToSet",也不需要增加计数器。

  2. 使用聚合可以很容易地以所需的形式调用数据。您可以实时执行此操作,也可以作为后台任务聚合到另一个集合

你可以这样聚合细节:

db.calls.aggregate([
    { "$group": {
        "_id": {
            "Owner": "$Owner",
            "WeekOfTheYear": { "$week": "$time" },
            "number": "$number"
        },
        "TotalDuration": { "$sum": "$duration" },
        "count": { "$sum": 1 }
    }},
    { "$group": {
        "_id": {
            "Owner": "$_id.Owner",
            "WeekOfTheYear": "$_id.WeekOfTheYear"
        },
        "calldetails": { "$push": {
            "number": "$_id.number",
            "TotalDuration": "$TotalDuration",
            "count": "$count"
        }},
        "totalDuration": { "$sum": "$TotalDuration" },
        "totalcalls": { "$sum": "$count" },
        "totaluniquecallers": { "$sum": 1 }
    }}
])

这两个阶段的分组以您想要的格式构建结果。当然,您想要做的是将第一个管道阶段添加到您想要查看的日期范围$match中,而不是处理所有结果,正如前面所述,理想情况下,您将这些结果作为后台任务添加到另一个集合中。

结论


尽管一开始保留某种"预先收集"的表单并在新事物出现时更新项目似乎是合乎逻辑的,但这并不容易做到,而且很快就会遇到并发问题。除此之外,这里维护数组条目的逻辑远比简单的更新复杂,并且需要大量的读取和更新,这加剧了并发问题。

因此,将其分解为一个简单的"一次性写入"集合并使用"后台聚合"可以通过引入简单的"仅插入"操作来添加细节来避免这些问题,并且后台任务不必在插入每个项目时发生。

因此,虽然它不是完全"实时"的,但通过仔细甚至处理,您可以"接近"收集到的详细信息的实时结果,并保持非常快速的写入操作。

总的来说,这是获得您想要的最终结果的最佳架构。

相关内容

  • 没有找到相关文章

最新更新