【问题标题】:Merge collections to get average rating, but still get all of original collection before a rating has been given. Mongoose / nodejs合并收藏以获得平均评级,但在给出评级之前仍会获得所有原始收藏。猫鼬/nodejs
【发布时间】:2015-03-20 18:13:12
【问题描述】:

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

我是一个菜鸟,主要玩前端,我很困惑我应该如何将这个示例代码更改为实际的生产代码。我看到每个功能在做什么,但仍然模糊不清。

我应该做一个 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;

cmets:

    '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}
});

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

    '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();
            });
    }
};

【问题讨论】:

  • 尝试一次只关注其中的一部分。你已经破坏了所有的服务器代码,所以只需在一个单独的隔离区域中使用,直到你做对为止。你在这里错位了很多。这些操作应该是“系列”而不是“瀑布”,因为你没有传递任何东西。他们还需要包装函数定义以传递回调以继续下一个。简而言之,您误解并从您复制的内容中删减了太多内容。
  • 好的。我会这样做的。
  • 这个更新的编辑是我所拥有的。我得到了 200,但结果没有任何 console.logs
  • 文档还应该返回一个空数组吗?

标签: javascript node.js mongodb mongoose


【解决方案1】:

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

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 个值放入哈希表(此处使用 nedb)中
  2. 从其他集合中获取聚合结果
  3. 使用实际具有值的项目更新所有项目的副本
  4. 当一切都完成后,你再读回你的哈希表

完整的工作示例:

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();
  }
);

按预期返回结果:

[ { 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 } ]

【讨论】:

  • @user3709602 您仍然在做错事,或者您的数据有问题。我已经发布了一个完整的工作清单,该清单是根据我给你的原始代码清单修改的。
  • 这是数据。我开始了,但我现在遇到的问题是页面刷新,它运行这个并复制每个波旁威士忌。
  • @user3709602 这又是另一个问题。但是我给你的代码没有错。当您应该“替换”时,您似乎在您的客户中做错了什么,例如“追加”。如果您无法解决,请发布另一个问题。我们不能只解决一个问题。请在您的个人资料中填写一些详细信息。匿名用户帐户让每个人都不敢回复 :)
  • 嘿,看看您是否对此线程有任何见解:stackoverflow.com/questions/28116054/…。在客户端尝试了我能想到的一切。想知道我是否应该在服务器端以某种方式实现 findAndModify。
猜你喜欢
  • 2015-03-07
  • 2018-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-14
  • 2021-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多