首页 文章

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

提问于
浏览
0

当我执行以下聚合时

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 = {} no limit no skip我得到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

    我的解决方案有点粗鲁,但我希望它能帮助您找到最佳解决方案 . 我使用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})
    
  • 0

    一种解决方案实际上是分两步执行,首先计数,然后使用限制/跳过进行聚合 . 这两个步骤可以与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"}
      }]]
    

相关问题