SailsJS和MongoDB聚合框架与自定义查询有关

Phi*_*vid 1 javascript mongodb mongodb-query aggregation-framework sails.js

我是MongoDB的新手,来自SQL背景.

我正在尝试这样做:

Get the top Artists, based on the number of Dubs.
Run Code Online (Sandbox Code Playgroud)

数据结构 :

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"
  },
  {...}
]
Run Code Online (Sandbox Code Playgroud)

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

[{
 _id: "548ef6215755950000a9a0de",
 name:"The Doors",
 total: 3
},{
 _id: "548ef6215715300000a9a1f9",
 name:"The Beatles",
 total: 0
}]
Run Code Online (Sandbox Code Playgroud)

我试过了 :

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);
  });
});
Run Code Online (Sandbox Code Playgroud)

哪能给我

[]
Run Code Online (Sandbox Code Playgroud)

而且:

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);
  });
});
Run Code Online (Sandbox Code Playgroud)

哪能给我

[ { _id: 'The Beatles', total: 1 },
{ _id: 'The Doors', total: 1 } ]
Run Code Online (Sandbox Code Playgroud)

谢谢

Nei*_*unn 8

您的第一个查询是在正确的轨道上,您正在使用错误的管道运算符.

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);
        }
})
Run Code Online (Sandbox Code Playgroud)

当然$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);
        }
})
Run Code Online (Sandbox Code Playgroud)

这通过计算数组的成员来做同样的事情,但是你需要$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"
}
Run Code Online (Sandbox Code Playgroud)

在每种情况下,您都可以获得所需的结果:

{
    "_id" : ObjectId("5494b79d7e22da84d53c8760"),
    "name" : "The Doors",
    "total" : 3
},
{
    "_id" : ObjectId("5494b79d7e22da84d53c8761"),
    "name" : "The Beatles",
    "total" : 0
}
Run Code Online (Sandbox Code Playgroud)