【问题标题】:mongoose aggregate : how to count matching documents and insert counting using Promises猫鼬聚合:如何使用 Promises 计算匹配文档和插入计数
【发布时间】:2017-12-10 05:21:10
【问题描述】:

当我执行以下聚合时

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 }
])

查询 = {} 没有限制没有跳过 我得到了 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 它可以并行完成。 .)

感谢反馈

【问题讨论】:

    标签: node.js mongoose aggregation-framework


    【解决方案1】:

    我的解决方案有点粗鲁,但我希望在找到最佳解决方案之前对您有所帮助。我使用 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})
    

    【讨论】:

    • 感谢您的反馈...这应该可以工作,但在我的情况下,我需要在 $limit/$skip 之前计算匹配的文档,否则最终输出 ROLES.length 将相等到$limit...我够清楚了吗?
    【解决方案2】:

    一种解决方案实际上是分两步执行,首先是counting,然后是通过limit/skip 聚合。这两个步骤可以作为 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"}
      }]]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-27
      • 2021-03-01
      • 2019-05-22
      • 1970-01-01
      • 2015-08-21
      • 2016-02-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多