You really should not "dot notation" for a an "array" key in the aggregation pipeline, but what you are doing is still perfectly valid. However you can reduce the array elements to just "id" values with $project
though:
Also looks like you might need to contruct your BSON for matching the ObjectId seperately:
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}}')
That now makes "likes" an array of just values and not a "key/value" pair. So you don't need "$likes.id" in later stages. Just reference by "$likes".
--
For the record, I went through this with a sample document is a collection like what you seem to have defined:
{
"_id" : ObjectId("50e99acfb35de75402002023"),
"likes" : [
{
"id" : ObjectId("50e99acfb35de75402002023")
},
{
"id" : ObjectId("50e99acfb35de75402002023")
},
{
"id" : ObjectId("50e99acfb35de75402002023")
},
{
"id" : ObjectId("50e99acfb35de75402002023")
}
]
}
Then I actually defined the pipeline in R using the bson.from.list` contructors like so:
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)
And for me that correctly adds all matching entries within the array.
Also "note" the additional match stage here after $unwind
. The first $match
in aggregation matches the "document", but this does nothing to "filter" the array content, so items in the array still contain things that do not match the "id" value you asked for.
So after processing $unwind
you need to "filter" with $match
again once the array has been denormalized. There are actually more efficient ways of doing this and they are well documented on this site even: Retrieve only the queried element in an object array in MongoDB collection
But you should also really be using the bson.from.list
and general list()
contructors for the structure rather than converting from JSON.