如何填充和聚合

时间:2017-06-05 09:32:33

标签: node.js mongodb mongoose aggregation-framework

我想汇总评分,以便我可以得到反馈的总数。但事实是,它被引用了。这是我的架构

用户

    username: String,
    fullname: String,
    email: {
        type: String,
        lowercase: true,
        unique: true
    },
  address: String,
  password: String,
  feedback: [{
      type: mongoose.Schema.Types.ObjectId,
      ref: 'Feedback'    
  }]

反馈

var FeedbackSchema = new mongoose.Schema({
    postname: String,
    user: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    },
    message: String,
    feedbacktype: String,
    thumbsup: Boolean,
    rating: {
        communication: Number,
        timeliness: Number,
        delivery: Number
    }
});

所以我想要实现的是,我将通过id找到用户,然后填充反馈字段,然后我将汇总反馈字段的评级,这样我就可以获得通信,交付和为了及时。 (评分为1-5星)

你知道如何聚合和填充吗?谢谢

**更新

所以我将聚合运行到用户架构,现在我从所有评级中得到0结果

User.aggregate([
  { "$match": { "_id": ObjectId('593150f6ac4d9b0410d2aac0') } },
  { "$lookup": {
    "from": "feedbacks",
    "localField": "feedback",
    "foreignField": "_id",
    "as": "feedback"
  }},
  { "$project": {
    "username": 1,
    "fullname": 1,
    "email": 1,
    "password": 1,
    "rating": {
      "communication": { "$sum": "$feedback.rating.communication" },
      "timeliness": { "$sum": "$feedback.rating.timeliness" },
      "delivery": { "$sum": "$feedback.rating.delivery" }
    }
  }}
]).exec(function(err, a){
    console.log(a)
})

结果rating: { communication: 0, timeliness: 0, delivery: 0 } } ]

也尝试过与其他用户一起使用,所有这些都是0结果评级

1 个答案:

答案 0 :(得分:1)

要遵循的简单列表

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

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

var userSchema = new Schema({
  username: String,
  feedback: [{ type: Schema.Types.ObjectId, ref: 'Feedback' }]
});

var feedbackSchema = new Schema({
  rating: {
    communication: Number,
    timeliness: Number,
    delivery: Number
  }
});

var User = mongoose.model('User', userSchema);
var Feedback = mongoose.model('Feedback', feedbackSchema);
async.series(
  [
    (callback) => {
      async.each([User,Feedback],(model,callback) => {
        model.remove({},callback);
      },callback);
    },

    (callback) => {
      async.waterfall(
        [
          (callback) => {
            async.map(
              [
                { "rating": {
                  "communication": 1, "timeliness": 2, "delivery": 3
                }},
                { "rating": {
                  "communication": 2, "timeliness": 3, "delivery": 4
                }}
              ],
              (item,callback) => {
                Feedback.create(item,callback)
              },
              callback
            );
          },
          (feedback, callback) => {
            User.create({ "username": "Bill", "feedback": feedback },callback);
          },
          (user, callback) => {
            User.aggregate([
              { "$match": { "_id": user._id } },
              { "$lookup": {
                "from": "feedbacks",
                "localField": "feedback",
                "foreignField": "_id",
                "as": "feedback"
              }},
              { "$project": {
                "username": 1,
                "rating": {
                  "communication": { "$sum": "$feedback.rating.communication" },
                  "timeliness": { "$sum": "$feedback.rating.timeliness" },
                  "delivery": { "$sum": "$feedback.rating.delivery" }
                }
              }}
            ],(err,results) => {
              console.log(JSON.stringify(results, undefined, 2));
              callback(err);
            });
          }
        ],
        callback
      )
    }
  ],
  (err) => {
    if (err) throw err;
    mongoose.disconnect();
  }
);

这将创建两个集合作为用户

{
        "_id" : ObjectId("593548455198ab3c09cf736b"),
        "username" : "Bill",
        "feedback" : [
                ObjectId("593548455198ab3c09cf7369"),
                ObjectId("593548455198ab3c09cf736a")
        ],
        "__v" : 0
}

反馈:

{
        "_id" : ObjectId("593548455198ab3c09cf7369"),
        "rating" : {
                "communication" : 1,
                "timeliness" : 2,
                "delivery" : 3
        },
        "__v" : 0
}
{
        "_id" : ObjectId("593548455198ab3c09cf736a"),
        "rating" : {
                "communication" : 2,
                "timeliness" : 3,
                "delivery" : 4
        },
        "__v" : 0
}

节目输出显示聚合:

[
  {
    "_id": "5935494a159c633c1b34807b",
    "username": "Bill",
    "rating": {
      "communication": 3,
      "timeliness": 5,
      "delivery": 7
    }
  }
]

如果两个依赖关系不够清楚,还要package.json

{
  "name": "ratings",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "async": "^2.4.1",
    "mongoose": "^4.10.4"
  }
}

原始答案

就我个人而言,我会从"反馈"因为你已经在那里记录了用户,实际上这种方式可以更好地扩展。

我们可以使用$lookup而不是使用填充,而是使用至少为3.2的MongoDB服务器版本:

Feedback.aggregate([
  { "$match": { "user": userId } },
  { "$group": {
    "_id": "$user",
    "communication": { "$sum": "$rating.communication" },
    "timeliness": { "$sum": "$rating.timeliness" },
    "delivery": { "$sum": "$rating.delivery" }
  }},
  { "$lookup": {
    "from": "users",
    "localField": "_id",
    "foreignField": "_id",
    "as": "user"
  }},
  { "$unwind": "$user" }
])

如果您没有支持$lookup的服务器版本,那么您仍然可以"手动加入"用户详细信息如下:

Feedback.aggregate([
  { "$match": { "user": userId } },
  { "$group": {
    "_id": "$user",
    "communication": { "$sum": "$rating.communication" },
    "timeliness": { "$sum": "$rating.timeliness" },
    "delivery": { "$sum": "$rating.delivery" }
  }}
],function(err, results) {
    result = results[0];
    User.findById(userId).lean().exec(function(err, user) {
      result.user = user;     // swap the _id for the Object

      // Then output result
    });
})

这基本上是.populate()的作用,但我们正在为返回的结果手动有效地进行此操作。

您可以使用User模型进行相反的工作,但这样做可能更有效率。

User.aggregate([
  { "$match": { "_id": userid } },
  { "$lookup": {
    "from": "feedbacks",
    "localField": "feedback",
    "foreignField": "_id",
    "as": "feedback"
  }},
  { "$project": {
    "username": 1,
    "fullname": 1,
    "email": 1,
    "password": 1,
    "rating": {
      "communication": { "$sum": "$feedback.rating.communication" },
      "timeliness": { "$sum": "$feedback.rating.timeliness" },
      "delivery": { "$sum": "$feedback.rating.delivery" }
    }
  }}
])