如何通过在 mongodb 中使用填充或使用聚合进行内部查询来使用填充功能

How to use populate functionality by using populate or making inner query with aggregation in mongodb

我的 Mongodb 中有以下数据。

 {
            "_id" : ObjectId("54a0d4c5bffabd6a179834eb"),
            "is_afternoon_scheduled" : true,
            "employee_id" : ObjectId("546f0a06c7555ae310ae925a")
 }

我想使用聚合填充,并想在同一个响应中获取员工的完整信息,我需要这方面的帮助。我的代码是:

var mongoose = require("mongoose");
var empid = mongoose.Types.ObjectId("54a0d4c5bffabd6a179834eb");
Availability.aggregate() 
    .match( { employee_id : empid} )
    .group({_id : "$employee_id",count: { $sum: 1 }})
    .exec(function (err, response) {
        if (err) console.log(err);
            res.json({"message": "success", "data": response, "status_code": "200"});
        }
);

我得到的回复是

{"message":"success","data":{"_id":"54a0d4c5bffabd6a179834eb","count":1},"status_code":"200"}

我的预期回复是:

{"message":"success","data":[{"_id":"54aa34fb09dc5a54232e44b0","count":1, "employee":{fname:abc,lname:abcl}}],"status_code":"200"}

您可以在聚合操作的结果对象上调用 .populate() 的模型形式。但问题是您需要一个模型来表示聚合返回的 "Result" 对象才能这样做。

有几个步骤,最好用完整的列表来解释:

var async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;


var employeeSchema = new Schema({
  "fname": String,
  "lname": String
})

var availSchema = new Schema({
  "is_afternoon_scheduled": Boolean,
  "employee_id": {
    "type": Schema.Types.ObjectId,
    "ref": "Employee"
  }
});

var resultSchema = new Schema({
  "_id": {
    "type": Schema.Types.ObjectId,
    "ref": "Employee"
  },
  "count": Number
});

var Employee = mongoose.model( "Employee", employeeSchema );
var Availability = mongoose.model( "Availability", availSchema );
var Result = mongoose.model( "Result", resultSchema, null );

mongoose.connect('mongodb://localhost/aggtest');

async.series(

  [
    function(callback) {
      async.each([Employee,Availability],function(model,callback) {
        model.remove({},function(err,count) {
          console.log( count );
          callback(err);
        });
      },callback);
    },

    function(callback) {
      async.waterfall(
        [
          function(callback) {
            var employee = new Employee({
              "fname": "abc",
              "lname": "xyz"
            });
            employee.save(function(err,employee) {
              console.log(employee),
              callback(err,employee);
            });
          },
          function(employee,callback) {
            var avail = new Availability({
              "is_afternoon_scheduled": true,
              "employee_id": employee
            });
            avail.save(function(err,avail) {
              console.log(avail);
              callback(err);
            });
          }
        ],
        callback
      );
    },

    function(callback) {
      Availability.aggregate(
        [
          { "$group": {
            "_id": "$employee_id",
            "count": { "$sum": 1 }
          }}
        ],
        function(err,results) {
          results = results.map(function(result) {
            return new Result( result );
          });

          Employee.populate(results,{ "path": "_id" },function(err,results) {
            console.log(results);
            callback(err);
          });
        }
      );
    }


  ],
  function(err,result) {
    if (err) throw err;
    mongoose.disconnect();
  }

);

这是完整的例子,但仔细看看聚合结果内部发生的事情才是重点:

        function(err,results) {
          results = results.map(function(result) {
            return new Result( result );
          });

          Employee.populate(results,{ "path": "_id" },function(err,results) {
            console.log(results);
            callback(err);
          });
        }

首先要注意的是 .aggregate() 返回的结果不是猫鼬文档,因为它们在 .find() 查询中。这是因为聚合管道通常会根据原始模式的外观更改结果中的文档。由于它只是一个原始对象,每个元素都被重新转换为前面定义的 Result 模型类型的 mongoose 文档。

现在,为了 .populate() 使用来自 Employee 的数据,在文档对象形式的 results 数组上调用此方法的模型形式以及 "path" 要填充的字段的参数。

最终结果填充的是来自与之相关的 Employee 模型的数据。

[ { _id:
     { _id: 54ab2e3328f21063640cf446,
       fname: 'abc',
       lname: 'xyz',
       __v: 0 },
    count: 1 } ]

与find的处理方式不同,但由于返回结果的方式,需要"re-cast"手动调用这种方式。

这就像使用内部查询使用聚合应用填充一样工作。

   var mongoose = require("mongoose");
    var empid = mongoose.Types.ObjectId("54a0d4c5bffabd6a179834eb");
    Availability.aggregate() 
        .match( { employee_id : empid} )
        .group({_id : "$employee_id",count: { $sum: 1 }})
        .exec(function (err, response) {
            if (err) console.log(err);
            if (response.length) {
                     var x = 0;
                    for (var i=0; i< response.length; i++) {
                          empID = response[i]._id;
                          if (x === response.length -1 ) {
                          User.find({_id: empID}, function(err, users){
                            res.json({"message": "success", "data": users, "status_code": "200"});
                          });
                          }
                          x++;
                    }
            }
        }
    );