【问题标题】:SailsJS & MongoDB Aggregation framework troubles with custom queriesSailsJS 和 MongoDB 聚合框架的自定义查询问题
【发布时间】:2014-12-15 21:26:37
【问题描述】:

我是 MongoDB 的新手,具有 SQL 背景。

我正在尝试这样做:

Get the top Artists, based on the number of Dubs.

数据结构:

Artists = [
  {
    "dubs": [{...},{...},{...}],
    "name": "The Doors",
    "createdAt": "2014-12-15T15:24:26.216Z",
    "updatedAt": "2014-12-15T15:24:26.216Z",
    "id": "548efd2a436c850000353f4f"
  },
  {
    "dubs": [],
    "name": "The Beatles",
    "createdAt": "2014-12-15T20:30:33.922Z",
    "updatedAt": "2014-12-15T20:30:33.922Z",
    "id": "548f44e90630d50000e2d61d"
  },
  {...}
]

所以我寻求的结果是这样的:

[{
 _id: "548ef6215755950000a9a0de",
 name:"The Doors",
 total: 3
},{
 _id: "548ef6215715300000a9a1f9",
 name:"The Beatles",
 total: 0
}]

我试过了:

Artist.native(function(err, collection) {

  collection.aggregate([ {
    $group: {
      _id: {
        name: "$name"
      },
      total: {
        $size: "$dubs"
      }
    }
  }, {
    $size: {
      total: -1
    }
  }], function(e, r) {
    if (e) res.serverError(e);
    console.log(r);
  });
});

这给了我

[]

还有:

Artist.native(function(err, collection) {
  if (err) return res.serverError(err);

  collection.aggregate({
    $group: {
      _id: "$name",
      total: {
        $sum: 1
      }
    }
  }, {
    $sort: {
      total: -1
    }
  }, function(e, r) {
    console.log(r);
    if (e) return res.serverError(e);
  });
});

这给了我

[ { _id: 'The Beatles', total: 1 },
{ _id: 'The Doors', total: 1 } ]

谢谢

【问题讨论】:

    标签: javascript mongodb mongodb-query sails.js aggregation-framework


    【解决方案1】:

    您的第一个查询是正确的,因为您使用了错误的管道运算符。

    Artist.native(function(err,collection) {
    
        collection.aggregate(
            [
                { "$project": {
                    "_id": 1,
                    "name": 1,
                    "total": { "$size": "$dubs" }
                }}
            ],
            function(err,result) {
              if (err) return res.serverError(err);
              console.log(result);
            }
    })
    

    当然,$size 运算符要求您需要 MongoDB 2.6 或更高版本,您现在可能应该这样做,但您仍然可以在没有运算符的情况下执行相同的操作来测量数组长度:

    Artist.native(function(err,collection) {
    
        collection.aggregate(
            [
                { "$project": {
                    "_id": 1,
                    "name": 1,
                    "dubs": {
                        "$cond": [
                           { "$eq": [ "$dubs", [] ] },
                           [0],
                           "$dubs"
                        ]
                    }
                }},
                { "$unwind": "$dubs" },
                { "$group": {
                    "_id": "$_id",
                    "name": { "$first": "$name" },
                    "total": { 
                        "$sum": {
                            "$cond": [
                                { "$eq": [ "$dubs", 0 ] },
                                0,
                                1
                            ]
                        }
                    }
                }}
            ],
            function(err,result) {
              if (err) return res.serverError(err);
              console.log(result);
            }
    })
    

    这通过计算数组的成员来做同样的事情,但是您需要$unwind 数组元素才能计算它们。所以它仍然可以完成,但效率不高。

    此外,由于$unwind 处理空数组[] 的方式,您需要处理数组真正为空但存在的情况。如果没有内容,那么包含此类元素的文档将从结果中删除。以类似的方式,您需要使用$ifNull 设置一个数组,其中文档甚至不包含$unwind 的元素,以免导致错误。

    真的,如果您打算定期进行此类查询,那么您应该在文档中维护一个“总计”字段,而不是先进行计算。使用$inc 运算符以及$push$pull 等操作来记录当前数组长度。

    这确实有点偏离了一般的 Waterline 理念,但是您已经引入了本机聚合操作,并且意识到您也可以通过在其他领域使用本机操作来获得更好的性能,这并不难。

    所以对于这样的文件:

    {
      "dubs": [{},{},{}],
      "name": "The Doors",
      "createdAt": "2014-12-15T15:24:26.216Z",
      "updatedAt": "2014-12-15T15:24:26.216Z",
      "id": "548efd2a436c850000353f4f"
    },
    {
      "dubs": [],
      "name": "The Beatles",
      "createdAt": "2014-12-15T20:30:33.922Z",
      "updatedAt": "2014-12-15T20:30:33.922Z",
      "id": "548f44e90630d50000e2d61d"
    }
    

    您在每种情况下都能得到您想要的结果:

    {
        "_id" : ObjectId("5494b79d7e22da84d53c8760"),
        "name" : "The Doors",
        "total" : 3
    },
    {
        "_id" : ObjectId("5494b79d7e22da84d53c8761"),
        "name" : "The Beatles",
        "total" : 0
    }
    

    【讨论】:

    • 哇,感谢您的长回答!我必须说我有点懒得添加一个新字段......即使它比查询更容易:P
    • 由于某种原因,total 总是为 0
    • @PhilippeDavid 添加了文档示例和以其他方式显示的结果。但这确实提醒我$unwind 示例并不像最初给出的那样完全正确。因此,这是通过进一步解释进行修改的。
    猜你喜欢
    • 2021-12-14
    • 2023-01-31
    • 2021-07-03
    • 2015-11-19
    • 1970-01-01
    • 1970-01-01
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多