使用MongoDB 2.4获取两个属性的不同列表

时间:2015-08-25 23:32:25

标签: mongodb mongodb-query aggregation-framework

我有一篇文章集:

{
    _id: 9999,
    authorId: 12345,
    coAuthors: [23456,34567],
    title: 'My Article'
},
{
    _id: 10000,
    authorId: 78910,
    title: 'My Second Article'
}

我正在试图找出如何从数据库中获取不同作者和共同作者ID的列表。我尝试过pushconcataddToSet,但似乎找不到合适的组合。我在2.4.6上,所以我无法访问setUnion

1 个答案:

答案 0 :(得分:1)

虽然$setUnion将成为"理想的"做到这一点的方法,还有另一种基本上涉及"切换"在"类型"之间交替选择哪个领域:

db.collection.aggregate([
    { "$project": {
        "authorId": 1,
        "coAuthors": { "$ifNull": [ "$coAuthors", [null] ] },
        "type": { "$const": [ true,false ] }
    }},
    { "$unwind": "$coAuthors" },
    { "$unwind": "$type" },
    { "$group": {
        "_id": {
            "$cond": [
                 "$type",
                 "$authorId",
                 "$coAuthors"
            ]
        }
    }},
    { "$match": { "_id": { "$ne": null } } }
])

就是这样。您可能会将$const操作知道为MongoDB 2.6中的$literal运算符。它一直存在,但只是记录在案并给出了别名"在2.6发布。

当然,两种情况下的$unwind操作都会产生更多的副本和#34;数据,但这是" distinct"价值所以没关系。只需依赖于预测"类型的true/false交替值"字段(一旦解开)你只需交替选择字段。

这个小mapReduce也做了同样的事情:

db.collection.mapReduce(
  function() {
    emit(this.authorId,null);
    if ( this.hasOwnProperty("coAuthors"))
      this.coAuthors.forEach(function(id) { 
        emit(id,null);
      });
  },
  function(key,values) {
    return null;
  },
  { "out": { "inline": 1 } }
)

为了记录,$setUnion当然要更清洁,更高效:

db.collection.aggregate([
    { "$project": {
        "combined": { 
            "$setUnion": [
                { "$map": {
                    "input": ["A"],
                    "as": "el",
                    "in": "$authorId"
                }},
                { "$ifNull": [ "$coAuthors", [] ] }
            ]
        }
    }},
    { "$unwind": "$combined" },
    { "$group": {
      "_id": "$combined"
    }}
])

所以唯一真正的问题是转换单数" authorId"通过$map到一个数组并在一个空数组中输入" coAuthors"字段不在文档中。

两者都从示例文档中输出相同的不同值:

{ "_id" : 78910 }
{ "_id" : 23456 }
{ "_id" : 34567 }
{ "_id" : 12345 }