如何在Mongodb中返回数组项的索引?

时间:2013-06-05 11:59:28

标签: mongodb

该文件如下所示。

{
    "title": "Book1",
    "dailyactiviescores":[
        {
            "date": 2013-06-05,
            "score": 10,
        },
        {
            "date": 2013-06-06,
            "score": 21,
        },
    ]
}

一旦读者打开书籍,每日活动分数就会增加。想到的第一个解决方案是使用“$”来查找目标日期是否有分数,然后处理它。

err = bookCollection.Update(
    {"title":"Book1", "dailyactivescore.date": 2013-06-06},
    {"$inc":{"dailyactivescore.$.score": 1}})
if err == ErrNotFound {
    bookCollection.Update({"title":"Book1"}, {"$push":...})
}

但我不禁想到有没有办法在数组中返回一个项目的索引?如果是这样,我可以使用一个查询来完成工作,而不是两个。像这样。

index = bookCollection.Find(
    {"title":"Book1", "dailyactivescore.date": 2013-06-06}).Select({"$index"})
if index != -1 {
    incTarget = FormatString("dailyactivescore.%d.score", index)
    bookCollection.Update(..., {"$inc": {incTarget: 1}})
} else {
    //push here
}

2 个答案:

答案 0 :(得分:2)

增加一个不存在的字段不是问题,因为执行$ inc:1只会创建它并将其设置为1后增量。问题是当您没有与要增加的日期对应的数组项时。

这里有几种可能的解决方案(不涉及多个增量步骤)。

一种方法是预先创建数组元素中的所有日期,分数为:0,如下所示:

{
    "title": "Book1",
    "dailyactiviescores":[
        {
            "date": 2013-06-01,
            "score": 0,
        },
        {
            "date": 2013-06-02,
            "score": 0,
        },
        {
            "date": 2013-06-03,
            "score": 0,
        },
        {
            "date": 2013-06-04,
            "score": 0,
        },
        {
            "date": 2013-06-05,
            "score": 0,
        },
        {
            "date": 2013-06-06,
            "score": 0
        },  { etc ... }
    ]
}

但是未来走多远?因此,这里的一个选项是“桶” - 例如,“每个月”有一个活动文档,并且在月初之前有一个创建下个月新文档的作业。有点难过。但它会奏效。

其他选项涉及架构的细微变化。

您可以使用包含book,date,activity_scores的集合。然后,您可以使用简单的upsert来增加分数:

   db.books.update({title:"Book1", date:"2013-06-02", {$inc:{score:1}}, {upsert:true})

这会增加分数或插入新记录,分数为:1本书和日期,您的收藏将如下所示:

{
    "title": "Book1",
    "date": 2013-06-01,
    "score": 10,
},
{
    "title": "Book1",
    "date": 2013-06-02,
    "score": 1,
}, ...

根据您从实际用例中简化示例的程度,这可能会很好。

另一个选择是坚持使用数组,但切换到使用日期字符串作为你增加的键:

架构:

{
    "title": "Book1",
    "dailyactiviescores":{
            { "2013-06-01":10},
            { "2013-06-02":8}
    }
 }

注意它现在是一个子文档而不是数组,你可以这样做:

db.books.update({title:"Book1"}, {"dailyactivityscores.2013-06-03":{$inc:1}})

它将在子文档中添加一个新日期并将其递增,从而产生:

{
    "title": "Book1",
    "dailyactiviescores":{
            { "2013-06-01":10},
            { "2013-06-02":8},
            { "2013-06-03":1}
    }
 }

请注意,现在更难以“累加”该书的分数,因此您可以原子地同时更新同一更新语句中的“小计”,无论是全部时间还是仅适用于本月。

但是,继续在这个子文档中添加天数再次成为问题 - 当你几年后仍然存在并且这些书籍文档大量增长时会发生什么?

我怀疑除非您只保留最近N天的活动分数(您可以使用2.4中的上限数组功能),否则为每本书的书籍活动分数跟踪设置单独的收集会更简单-day是一个单独的文件,而不是将每天的分数嵌入到书中的书中。

答案 1 :(得分:1)

根据文件:

  

$ inc运算符将字段值增加指定的量。   如果该字段不存在,$ inc将字段设置为指定的字段   量。

因此,如果数组项中不存在score字段,$inc会在您的情况下将其设置为1,如下所示:

{
    "title": "Book1",
    "dailyactiviescores":[
        {
            "date": 2013-06-05,
            "score": 10,
        },
        {
            "date": 2013-06-06,
        },
    ]
}

bookCollection.Update(
    {"title":"Book1", "dailyactivescore.date": 2013-06-06},
    {"$inc":{"dailyactivescore.$.score": 1}})

将导致:

{
    "title": "Book1",
    "dailyactiviescores":[
        {
            "date": 2013-06-05,
            "score": 10,
        },
        {
            "date": 2013-06-06,
            "score": 1
        },
    ]
}

希望有所帮助。