我有一个元素列表。一些_parentId属性指向同一集合中元素的id。因此,所有具有_parentId的元素都是那些没有_parentId的元素的子元素。
我需要一个结果,它包含所有父元素(没有_parentId),子元素的数量以及每个父元素的最新添加(它有一个dateCreated属性)子元素的“content”属性。例如:
[{
_id: "some id",
title: "some title",
email: "some email",
dateCreated: "date",
children:{
count: 7,
lastAddedChildContent: "some content",
dateCreated: "date:
}],
parentCount:23 // total for parent elements
}
最好的方法是什么? 谢谢!
答案 0 :(得分:3)
公平的问题。仅仅为了示例目的简化文档,比如说有这样的文档:
{
"_id" : ObjectId("53ed7efca75ca1a5248a281a"),
"dateCreated" : ISODate("2014-08-15T03:46:57.784Z"),
"title" : "Master",
"content" : "Orig content"
}
{
"_id" : ObjectId("53ed80bba75ca1a5248a281b"),
"title" : "Other title",
"content" : "More content",
"dateCreated" : ISODate("2014-08-15T03:38:35.694Z"),
"_parent" : ObjectId("53ed7efca75ca1a5248a281a")
}
{
"_id" : ObjectId("53ed80d1a75ca1a5248a281c"),
"title" : "Other title",
"content" : "Last content",
"dateCreated" : ISODate("2014-08-15T03:38:57.750Z"),
"_parent" : ObjectId("53ed7efca75ca1a5248a281a")
}
您的聚合管道基本上会将_id
字段替换为父项,然后对结果进行排序:
db.collection.aggregate([
{ "$project": {
"_id": { "$ifNull": [ "$_parent", "$_id" ] },
"title": 1,
"dateCreated": 1,
"content": 1,
"_parent": { "$ifNull": [ "$_parent", false ] }
}},
{ "$sort": { "_id": 1, "_parent": -1, "dateCreated": 1 } },
{ "$group": {
"_id": "$_id",
"title": { "$min": { "$cond": [ "$_parent", false, "$title" ] } },
"dateCreated": {
"$max": {
"$cond": [
"$_parent",
false,
"$dateCreated"
]
}
},
"childCount": {
"$sum": {
"$cond": [
"$_parent",
1,
0
]
}
},
"lastContent": { "$last": "$content" },
"lastDate": { "$last": "$dateCreated" }
}},
{ "$project": {
"title": 1,
"dateCreated": 1,
"children": {
"count": "$childCount",
"lastContent": "$lastContent",
"dateCreated": "$lastDate"
}
}}
])
由此产生的反应是:
{
"_id" : ObjectId("53ed7efca75ca1a5248a281a"),
"title" : "Master",
"dateCreated" : ISODate("2014-08-15T03:46:57.784Z"),
"children" : {
"count" : 2,
"lastContent" : "Last content",
"dateCreated" : ISODate("2014-08-15T03:38:57.750Z")
}
}
要查看的主要运算符是$ifNull
,它们测试字段存在或实际上是null
值,并返回字段内容或备用参数。另一个是$cond
,它是三元运算符。它评估逻辑条件或值作为它的第一个参数,然后在该参数为true
的情况下返回第二个参数,或者在false
的情况下返回最后一个参数。在现代版本中,这甚至可以写成" if .. then .. else"如果这看起来更清楚。
最初的$project
用于提供$sort
的信息,这基本上是完成的,因为您需要$last
运算符构成您的响应的一部分。
在$group
声明中,属于" parent"的所有文件现在与父进程具有相同的_id
,这是正确的分组键。任何"父字段"有条件地评估,以便只返回该内容,这是**$min
在$sum
上的创造性用法,作为"字符串"仅为"父母"文档,其值将小于false
,否则返回。
"计数"儿童是简单的评估文件是否是父母"在选择要提供给{{3}}的值时是否。其他字段以及count将使用排序顺序中的$last
进行评估,并且全部单独返回,因为您无法返回"子文档"在聚合组中形成。这些$project
稍后会进入所需的输出。
我故意搞砸了那里的日期以展示"排序"原则,但这主要是关于父母"鉴定。另一个故意的行动不是将所有父母和#34;成阵列。我不认为这是一个很好的做法,只是为了得到一个计数,并且它确实有可能打破16MB的BSON限制。如果您希望响应看起来像发送到其他地方那样,最好进行后期处理并添加计数,因为您不会有相同的限制并且可以使用尽可能多的内存。
所以,如果你必须,那么另外一组添加到" push"和"计数"最后,但是如果出现问题,不要说你没有得到更好的建议。