通过匹配rmongodb中的ObjectId进行聚合

时间:2015-07-17 09:04:52

标签: r mongodb aggregation-framework rmongodb

我遇到涉及ObjectId的聚合问题。这是管道:

{'$match' : {'likes.id' : ObjectId('50e99acfb35de75402002023')}}
{'$project' : {'likes.id' : 1, '_id' : 0}}
{'$unwind' : '$likes'}
{'$group' : {'_id' : '$likes.id', 'count' : {'$sum':1}}}
{'$sort' : {'_id' : 1}}

我尝试使用rmongodb在R中编写它是:

pipe_1 <- mongo.bson.from.JSON('{"$match" : {"likes.id" : { "$oid" : "50e99acfb35de75402002023" }}}')
pipe_2 <- mongo.bson.from.JSON('{"$project" : {"likes.id" : 1, "_id" : 0}}')
pipe_3 <- mongo.bson.from.JSON('{"$unwind" : "$likes"}')
pipe_4 <- mongo.bson.from.JSON('{"$group" : {"_id" : "$likes.id", "count" : {"$sum":1}}}')
pipe_5 <- mongo.bson.from.JSON('{"$sort" : {"count" : 1}}')
pipes <- list(pipe_1,pipe_2,pipe_3,pipe_4,pipe_5)
result <- mongo.aggregation(mongo, ns = "analytics.analytics_profiles", pipeline =pipes)

返回

mongoDB error: 10

与BSON无效错误代码对应。

我认为问题在于ObjectId的匹配:第一个管道单独给出了相同的错误。

我该如何解决这个问题?

额外:如何使用蒙古石代替呢?

1 个答案:

答案 0 :(得分:3)

对于聚合管道中的“数组”键,你真的不应该“点符号”,但你所做的仍然是完全有效的。但是,您可以使用$project将数组元素减少为“id”值,但是:

看起来您可能需要构建您的BSON以单独匹配ObjectId:

oid <- mongo.oid.from.string("50e99acfb35de75402002023")
pipe_1 <- mongo.bson.from.list(list('$match' = list('likes.id' =  oid)))
pipe_2 <- mongo.bson.from.JSON('{"$project" : {"likes" : "$likes.id", "_id" : 0}}')
pipe_3 <- mongo.bson.from.JSON('{"$unwind" : "$likes"}')
pipe_4 <- mongo.bson.from.list(list('$match' = list('likes' =  oid)))
pipe_5 <- mongo.bson.from.JSON('{"$group" : {"_id" : "$likes", "count" : {"$sum":1}}}')
pipe_6 <- mongo.bson.from.JSON('{"$sort" : {"count" : 1}}')

现在,“喜欢”只是一组数值,而不是“键/值”对。因此,您不需要在以后阶段使用“$ likes.id”。只需参考“$ likes”。

-

为了记录,我通过一个示例文档来完成这个集合就像你似乎定义的那样:

{
    "_id" : ObjectId("50e99acfb35de75402002023"),
    "likes" : [
            {
                    "id" : ObjectId("50e99acfb35de75402002023")
            },
            {
                    "id" : ObjectId("50e99acfb35de75402002023")
            },
            {
                    "id" : ObjectId("50e99acfb35de75402002023")
            },
            {
                    "id" : ObjectId("50e99acfb35de75402002023")
            }
    ]
}

然后我实际上使用bson.from.list`构造函数在R中定义了管道,如下所示:

pipeline <- list(
    mongo.bson.from.list(list(
        '$match' =  list( 
           'likes.id' = mongo.oid.from.string("50e99acfb35de75402002023")
         )
    )),
    mongo.bson.from.list(list(
        '$project' = list(
            '_id' = 0,
            'likes' = '$likes.id'
        )
    )),
    mongo.bson.from.list(list(
        '$unwind' = '$likes'
    )),
    mongo.bson.from.list(list(
        '$match' =  list( 
           'likes' = mongo.oid.from.string("50e99acfb35de75402002023")
         )
    )),
    mongo.bson.from.list(list(
        '$group' = list(
            '_id' = '$likes',
            'count' = list( '$sum' = 1 )
        )
    )),
    mongo.bson.from.list(list(
        '$sort' = list( 'count' = 1 )
    ))
)

mongo.aggregation(mongo, "test.posts", pipeline)

对我来说,正确地添加了数组中的所有匹配条目。

在“{1}}之后”还“注意”此处的其他匹配阶段。聚合中的第一个$unwind与“文档”匹配,但这不会“过滤”数组内容,因此数组中的项目仍包含与您要求的“id”值不匹配的内容。

因此,在处理$match之后,一旦数组被非规范化,您需要再次使用$unwind“过滤”。实际上有更有效的方法可以做到这一点,甚至在Retrieve only the queried element in an object array in MongoDB collection

这个网站上都有详细记录

但是你也应该在结构中使用$match和一般bson.from.list构造函数,而不是从JSON转换。