合并集合以获得平均评级,但在给出评级之前仍然获得所有原始集合。猫鼬/节点

Merge collections to get average rating, but still get all of original collection before a rating has been given. Mongoose / nodejs

我有一个创建项目(波本威士忌)的管理员,用户可以在该评论中发表评论和评分。我能够汇总评论,但无法显示新创建的波旁威士忌,只能显示那些已经播种且已经有评级的波旁威士忌。我试图实现类似于此线程的东西:,但我没有做正确的事情。

我是菜鸟,主要玩前端,很迷茫如何把这个示例代码改成实际的生产代码。我看到每个功能在做什么,但仍然模糊不清。

我是否应该执行 async.each 并将聚合函数设置为迭代器..?我知道这是坏了。我现在已经尝试了一些东西。不断收到 500 错误,console.log 上什么也没有。对这个菜鸟的任何帮助,非常感谢。

这是我的架构: 波旁威士忌:

'use strict';

var mongoose = require('mongoose'),
    BourbonSchema = null;

module.exports = mongoose.model('Bourbon', {
    name:  {type: String, required: true},
    blog:  {type: String, required: true},
    photo: {type: String, required: true, default:'http://aries-wineny.com/wp-content/uploads/2014/09/woodford-reserve.jpg'},
    location: {type: String, required: true},
    distillery: {type: String, required: true},
    avgRating: {type: Number}
});

var Bourbon = mongoose.model('Bourbon', BourbonSchema);
module.exports = Bourbon;

评论:

    'use strict';

var mongoose = require('mongoose');

module.exports = mongoose.model('Comment', {
    bourbonId:   {type: mongoose.Schema.ObjectId, ref: 'Bourbon'},
    userId:   {type: mongoose.Schema.ObjectId, ref: 'User'},
    text:     {type: String, required: true},
    createdAt: {type: Date,  required: true, default: Date.now},
    rating  : {type: Number, required: true},
    votes:     {type: Number, default: 0}
});

这是我在控制器中的查找/获取,我尝试从引用的 link 拼凑起来,但现在很草率:

    'use strict';

var Bourbon = require('../../../models/bourbon'),
    Comment = require('../../../models/comment'),
    DataStore = require('nedb'),
    db = new DataStore(),
    async = require('async');

module.exports = {
    description: 'Get Bourbons',
    notes: 'Get Bourbons',
    tags: ['bourbons'],
    handler: function(request, reply){

        async.waterfall(
            [
                function(comment,callback){
                    async.series(
                        [

                            function(callback){
                                Bourbon.find({},function(err,results){
                                    async.eachLimit(results,10,function(result,callback){
                                        db.insert({
                                            'bourbonId': result._id.toString(),
                                            'location' : result.location,
                                            'blog'     : result.blog,
                                            'distillery': result.distillery,
                                            'name': result.name,
                                            'avgRating': 0
                                        },callback);
                                    },callback);
                                });
                            },

                            function(callback){
                                Comment.aggregate(
                                    [
                                        {'$group':{
                                            '_id': '$bourbonId',
                                            'avgRating':{
                                                '$avg':'$rating'
                                            }
                                        }}
                                    ],
                                    function(err,results){
                                        async.eachLimit(results,10,function(result,callback){
                                            db.update(
                                                {'bourbonId': result._id.toString()},
                                                {'$set':{
                                                    'avgRating': result.avgRating
                                                }
                                                },
                                                callback
                                            );
                                        },callback);
                                    }
                                );
                            }
                        ],
                    function(err) {
                        if (err) callback(err);
                        db.find({},{'_id': 0},callback);
                    }
                    );
                }
            ],
            function(err,results){
                reply({results: results});
                console.log('LOOOOOOOOOOOOOOOOK',JSON.stringify(results, undefined, 4));
                process.exit();
            });
    }
};

看来您还有更多关于回调和排序的知识要学习。这是您需要的请求处理程序中的所有代码。当然,当您看到正在发生的事情时更改为发送响应。

async.series(
  [
    // List out exiting collection with 0 average
    function(callback) {
      Bourbon.find({},function(err,results){
        async.eachLimit(results,10,function(result,callback){
          var plain = result.toObject()
          plain.bourbonId = plain._id.toString();
          plain.avgRating = 0;
          delete plain._id;

          db.insert(plain,callback); // next each iteration
        },callback);                  // move to next in series
      });
    },

    // Get aggregate results and update the items you just wrote
    function(callback) {
      Comment.aggregate(
        [
          { '$group': {
            '_id': '$bourbonId',
            'avgRating':{ '$avg':'$rating' }
          }}
        ],
        function(err,results) {
          async.eachLimit(results,10,function(result,callback){
            db.update(
              {  'bourbonId': result._id.toString() },
              {'$set': {'avgRating': result.avgRating } },
              callback                   // next each iteration
            );
          },callback);                   // next in series "last"  
        }
      );
    }
  ],
  // This is called when both in the series are complete
  function(err) {
    if (err) callback(err);
    db.find({},{'_id': 0},function(err,docs) {
        console.log( docs );
    });
  }
);

这里的目的是:

  1. 将 0 个值放入所有项目的散列 table(此处使用 nedb)
  2. 从其他集合获取聚合结果
  3. 用实际具有值的项目更新所有项目的副本
  4. 当一切都完成后,你读回你的散列table

完整的工作示例:

var async = require('async'),
    mongoose = require('mongoose'),
    DataStore = require('nedb'),
    db = new DataStore(),
    Schema = mongoose.Schema;

var userSchema = new Schema({
  "name": String
});

var ratingSchema = new Schema({
  "bourbonId": { "type": Schema.Types.ObjectId, "ref": "Bourbon" },
  "userId": { "type": Schema.Types.ObjectId, "ref": "User" },
  "rating": { "type": Number, "required": true }
});

var bourbonSchema = new Schema({
  "name": { "type": String, "required": true },
  "blog": { "type": String, "required": true },
  "photo": { "type": String, "required": true },
  "ratings": [{ "type": Schema.Types.ObjectId, "ref": "Rating" }],
  "rating": { "type": Number }
});

var User = mongoose.model( "User", userSchema ),
    Rating = mongoose.model( "Rating", ratingSchema ),
    Bourbon = mongoose.model( "Bourbon", bourbonSchema );


mongoose.connect("mongodb://localhost/bourbon");

async.waterfall(
  [
    function(callback) {
      async.each([User,Rating,Bourbon],function(model,callback) {
        model.remove({},callback);
      },
      function(err) {
        callback(err);
      });
    },

    function(callback) {
      Bourbon.create({
        "name": 'test',
        "blog": 'test',
        "photo": 'test'
      },callback);
    },

    function(bourbon,callback) {
      Bourbon.create({
        "name": 'another',
        "blog": 'another',
        "photo": 'another'
      },callback);
    },

    function(bourbon,callback) {
      User.create({ "name": 'ted' },function(err,user) {
        if (err) callback(err);
        Rating.create({
          "bourbonId": bourbon,
          "userId": user,
          "rating": 5
        },function(err,rating1) {
          callback(err,user,bourbon,rating1)
        });
      });
    },

    function(user,bourbon,rating1,callback) {
      Rating.create({
        "bourbonId": bourbon,
        "userId": user,
        "rating": 7
      },function(err,rating2) {
        callback(err,bourbon,rating1,rating2);
      });
    },

    function(bourbon,rating1,rating2,callback) {
      Bourbon.findById(bourbon.id,function(err,bourbon) {
        bourbon.ratings.push(rating1,rating2);
        bourbon.save(function(err,bourbon) {
          callback(err)
        });
      });
    },

    function(callback) {
      async.series(
        [
          function(callback) {
            Bourbon.find({},function(err,results) {
              if (err) callback(err);
              async.eachLimit(results,10,function(result,callback) {
                var plain = result.toObject();
                plain.bourbonId = plain._id.toString();
                plain.avgRating = 0;
                delete plain._id;

                db.insert(plain,callback);
              },callback);
            });
          },

          function(callback) {
            Rating.aggregate(
              [
                { "$group": {
                  "_id": "$bourbonId",
                  "avgRating": { "$avg": "$rating" }
                }}
              ],
              function(err,results) {
                if (err) callback(err);
                async.eachLimit(results,10,function(result,callback) {
                  db.update(
                    { "bourbonId": result._id.toString() },
                    { "$set": { "avgRating": result.avgRating } },
                    callback
                  );
                },callback);
              }
            );
          }
        ],
        function(err) {
          if (err) callback(err);
          db.find({},{ '_id': 0 },callback);
        }
      );
    }

  ],
  function(err,results) {
    if (err) throw err;
    console.log( results );
    mongoose.disconnect();
  }
);

Returns 结果符合预期:

[ { name: 'test',
    blog: 'test',
    photo: 'test',
    __v: 0,
    ratings: [],
    bourbonId: '54c17bea8aa5f8c9161f5b6e',
    avgRating: 0 },
  { name: 'another',
    blog: 'another',
    photo: 'another',
    __v: 1,
    ratings: [ [Object], [Object] ],
    bourbonId: '54c17bea8aa5f8c9161f5b6f',
    avgRating: 6 } ]