mongoose aggregate:如何计算匹配文档并使用Promises插入计数

时间:2017-07-06 09:25:08

标签: node.js mongoose aggregation-framework

当我执行以下聚合

return this.aggregate([
  {
    $lookup: {
      from: 'groups',
      localField: '_group',
      foreignField: '_id',
      as: 'group'
    }
  },
  { $match: query },
  {
    $project: {
      group: {
        $let:{
          vars:{
            firstGroup:{
              $arrayElemAt:["$group",0]
            }
          },
          in:{
            name:"$$firstGroup.name",
            description:"$$firstGroup.description"
          }
        }
      },
      name: 1,
      description: 1,
      _id: 0
    }
  },
  { $sort: sortBy },
  { $limit: resultsPerPage },
  { $skip: skipDocuments }
])

with query = {} 没有限制没有跳过 我得到8个匹配的角色,按group.name

分组
ROLES: [
{"name":"NewRole","description":"NewRole description","group":{}},{"name":"Visitor","description":"no permissions","group":{}},
{"name":"NewRoleInGroup","description":"NewRoleInGroup description","group":{"name":"GroupA","description":"Description GroupA"}},
{"name":"admin","description":"can RW group, user","group":{"name":"GroupA","description":"Description GroupA"}},
{"name":"employee","description":"can R group, can read user","group":{"name":"GroupA","description":"Description GroupA"}},
{"name":"manager","description":"can R group, can RW user","group":{"name":"GroupA","description":"Description GroupA"}},
{"name":"employee","description":"can R group, can read user","group":{"name":"GroupB","description":"Description GroupB"}},
{"name":"manager","description":"can R group, can RW user","group":{"name":"GroupB","description":"Description GroupB"}},
{"name":"employee","description":"can R group, can read user","group":{"name":"GroupC","description":"Description GroupC"}}
]

现在我想将总匹配文档作为结果中的第一个对象插入以跟踪它(当在聚合中指定限制时,我应该返回文档总数)

ROLES: [
{"roleCount": 8},
{"name":"NewRole","description":"NewRole description","group":{}},{"name":"Visitor","description":"no permissions","group":{}},
{"name":"NewRoleInGroup","description":"NewRoleInGroup description","group":{"name":"GroupA","description":"Description GroupA"}},
{"name":"admin","description":"can RW group, user","group":{"name":"GroupA","description":"Description GroupA"}},
{"name":"employee","description":"can R group, can read user","group":{"name":"GroupA","description":"Description GroupA"}}
]

我应该在管道中写入计数(我想在$ match之后?)  以及如何将计数插入结果? (我想在$ sort之后?)

也许没有办法在一个聚合中执行它,唯一的可能性是首先执行集合计数然后执行聚合并在返回结果之前插入计数器对象(使用Promise.all它可以并行完成)。 。)

感谢您的反馈

2 个答案:

答案 0 :(得分:0)

我的解决方案有点粗鲁,但我希望它能帮助您找到最佳解决方案。我使用lodash或者可以是原生的javascript。它的手柄看起来像这样!

    ROLES: [
         {"name":"NewRole","description":"NewRole description","group":{}},{"name":"Visitor","description":"no permissions","group":{}},
         {"name":"NewRoleInGroup","description":"NewRoleInGroup description","group":{"name":"GroupA","description":"Description GroupA"}},
         {"name":"admin","description":"can RW group, user","group":{"name":"GroupA","description":"Description GroupA"}},
         {"name":"employee","description":"can R group, can read user","group":{"name":"GroupA","description":"Description GroupA"}},
         {"name":"manager","description":"can R group, can RW user","group":{"name":"GroupA","description":"Description GroupA"}},
         {"name":"employee","description":"can R group, can read user","group":{"name":"GroupB","description":"Description GroupB"}},
         {"name":"manager","description":"can R group, can RW user","group":{"name":"GroupB","description":"Description GroupB"}},
         {"name":"employee","description":"can R group, can read user","group":{"name":"GroupC","description":"Description GroupC"}}
    ];
    ROLES.unshift({"roleCount": ROLES.length})

答案 1 :(得分:0)

实际上,一个解决方案是分两步执行,首先计数,然后使用限制/跳过进行聚合。这两个步骤可以作为Promise与Promise.all并行运行,然后返回两个结果(计数和数据)

  list(query, pageNumber, resultsPerPage, skipDocuments, sortBy) {

    const counting = this.count()
      .then((count) => {
        return {"roles": count};
      })
      .catch((e) => { throw(e); });
    const aggregation = this.aggregate([
      { $lookup: { from: 'groups', localField: '_group', foreignField: '_id', as: 'group'} },
      { $match: query },
      { $project: { group: { $let:{ vars:{ firstGroup:{ $arrayElemAt:["$group",0] } },  in:{ name:"$$firstGroup.name", description:"$$firstGroup.description" } } }, name: 1, description: 1, _id: 0 } },
      { $sort: sortBy },
      { $skip: skipDocuments },   // SKIP ALWAYS BEFORE LIMIT !
      { $limit: resultsPerPage }
    ]).exec()
      .then((list) => {
        return list;
      })
      .catch((e) => {
        console.log('MongoDB Error: ', e);
        return new APIError('Cannot list roles!', httpStatus.UNPROCESSABLE_ENTITY);
      });

    return Promise.all([counting, aggregation])
      .then((values) => {
        console.log('VALUES: %j', values);

返回值;           })           .catch((e)=> {throw(e);});       },

所以我们得到了确切的结果:

  VALUES: [
  {"roles":9},
  [{"name":"NewRole","description":"NewRole description","group":{}},{
  "name":"Visitor","description":"no permissions","group":{}},
  {"name":"NewRoleInGroup","description":"NewRoleInGroup description","group":{"name":"GroupA","description":"Description GroupA"}},
  {"name":"admin","description":"can RW group, user","group":{"name":"GroupA","description":"Description GroupA"}},
  {"name":"employee","description":"can R group, can read user","group":{"name":"GroupA","description":"Description GroupA"}},
  {"name":"manager","description":"can R group, can RW user","group":{"name":"GroupA","description":"Description GroupA"}},
  {"name":"employee","description":"can R group, can read user","group":{"name":"GroupB","description":"Description GroupB"}},
  {"name":"manager","description":"can R group, can RW user","group":{"name":"GroupB","description":"Description GroupB"}},
  {"name":"employee","description":"can R group, can read user","group":{"name":"GroupC","description":"Description GroupC"}
  }]]