如何在猫鼬/节点中获得平均评分
How to get a rating average in Mongoose / node
我在 angularjs 的前端有一个星级评级指令,我可以将评级保存到评级集合中。
这是我的评分模式/模型:
var mongoose = require('mongoose');
module.exports = mongoose.model('Rating', {
bourbonId: {type: mongoose.Schema.ObjectId, ref: 'Bourbon'},
userId: {type: mongoose.Schema.ObjectId, ref: 'User'},
rating: {type: Number, required: true},
ratingId : {type: mongoose.Schema.ObjectId}
});
这是我需要平均评分的项目:
'use strict';
var mongoose = require('mongoose'),
BourbonSchema = null;
module.exports = mongoose.model('Bourbon', {
BourbonId: {type: mongoose.Schema.ObjectId},
name: {type: String, required: true},
blog: {type: String, required: true},
photo: {type: String, required: true},
ratings: {type: mongoose.Schema.ObjectId, ref: 'Rating'},
rating: {type: Number}
});
var Bourbon = mongoose.model('Bourbon', BourbonSchema);
module.exports = Bourbon;
我需要找到一种通过波旁 ID 进行匹配的方法。从堆栈溢出来看,似乎使用聚合函数可能是可行的方法。 stack overflow link
这是我控制器中的当前损坏代码。我知道它还有很长的路要走,以及我使用 async.map 尝试解决此问题的失败尝试:
'use strict';
var Bourbon = require('../../../models/bourbon'),
Rating = require('../../../models/rating');
//async = require('async');
module.exports = {
description: 'Get Bourbons',
notes: 'Get Bourbons',
tags:['bourbons'],
handler: function(request, reply){
Bourbon.find(function(err, bourbons){
Bourbon.findOne(id, 'Rating', function(err, bourbon){
Rating.aggregate([
{$match: {bourbonId: {$in: bourbon.ratings}}},
{$group: {bourbonId: bourbon._id, average: {$avg: '$rating'}}}
], function(err, result){
bourbon.rating = result;
reply({bourbons:bourbons});
console.log('Bourbs', bourbons);
});
});
});
}
};
如有任何帮助,我们将不胜感激。把我的头撞在砖墙上,现在只是扔出随机代码。 ..
这是我实现的:
型号:
'use strict';
var mongoose = require('mongoose'),
BourbonResultSchema = null;
module.exports = mongoose.model('BourbonResult', {
_Id: {type: mongoose.Schema.ObjectId, 'ref': 'Bourbon'},
avgRating: {type: Number}
});
var BourbonResult = mongoose.model('BourbonResult', BourbonResultSchema, null);
module.exports = BourbonResult;
控制器:
'use strict';
var Bourbon = require('../../../models/bourbon'),
Rating = require('../../../models/rating'),
BourbonResult = require('../../../models/bourbonResult');
//async = require('async');
module.exports = {
description: 'Get Bourbons',
notes: 'Get Bourbons',
tags:['bourbons'],
handler: function(request, reply){
Rating.aggregate(
[
{'$group':{
'_id': '$bourbonId',
'avgRating': {'$avg': '$rating'}
}}
],
function(err,bourbons){
// Map plain results to mongoose document objects
bourbons = bourbons.map(function(result){
return new BourbonResult(result);
});
Bourbon.populate(bourbons,{'path': '_id'},function(err,bourbons){
reply({bourbons:bourbons});
console.log('BourbsRESSSSSS', JSON.stringify(bourbons, undefined, 2));
});
}
);
}
};
这是我从控制台日志返回的内容:
BourbsRESSSSSS [ { _id:
{ _id: 54acf382894ee2bcdebbc7f5,
name: 'example2',
photo: 'http://aries-wineny.com/wp-content/uploads/2014/09/woodford-reserve.jpg',
blog: 'example2',
__v: 0 },
avgRating: 3.3333333333333335 },
{ _id:
{ _id: 54a77e0fe63c850000f1269c,
name: 'example',
photo: 'http://aries-wineny.com/wp-content/uploads/2014/09/woodford-reserve.jpg',
blog: 'example',
__v: 0 },
avgRating: 3 } ]
============================================= ===========================
完美!
如果您要做的是在您的输出中列出每个 "Bourbon" 的 "average" 评级,可能有几种方法。但更简洁的方法之一是在表示聚合结果结构的特殊对象模型上使用 mongoose 填充。
除了 "bourbon" 之外,您在 "Ratings" 中似乎没有任何其他 "types",因此按理说您只想汇总整个集合。
// Set up a schema and model to match result structure
var bourbonResultSchema = new Schema({
"_id": { "type": Schema.Types.ObjectId, "ref": "Bourbon" },
"avgRating": Number
});
// The "null" for the collection is because there will not be any physical storage
var BourbonResult = mongoose.model( "BourbonResult", bourbonResultSchema, null );
// Aggregate an mapping code
Rating.aggregate(
[
{ "$group": {
"_id": "$bourbonId",
"avgRating": { "$avg": { "$ifNull": ["$rating",0 ] } }
}}
],
function(err,results) {
if (err) throw err;
// Map plain results to mongoose document objects
results = results.map(function(result) {
return new BourbonResult(result);
});
Bourbon.populate(results,{ "path": "_id" },function(err,results) {
if (err) throw err;
reply(results);
console.log( JSON.stringify( results, undefined, 2 ) );
})
}
);
因此,您定义了一个架构和模型,该架构和模型将匹配return聚合结果的结构。这样做是为了稍后您可以调用 .populate()
。
return聚合的结果不是 mongoose 文档,而是普通对象。然后,通过 .map()
方法将所有结果传递给 BourbonResult
对象,以便 return 一个 BourbonResult
.
数组
由于这些不是 mongoose 文档,您可以调用 .populate()
的模型方法,该方法将 mongoose 文档数组作为第一个参数。第二个 "options" 参数告诉方法将哪个字段路径用于填充,即前面定义的 _id
以引用 Bourbon
模型。
在 .populate()
的回调中,returned 结果合并了聚合的平均得分 return 和 [=18= 中的完整 Bourbon
对象] 场地。如果您真的愿意,您还可以 运行 在每个 Bourbon
对象上进一步 .populate()
语句,以便引入它的任何引用。有点复杂但可能。
请注意,"Bourbon" 模型中的 "bourbonId" 字段可能有点多余。 MongoDB 总是有一个唯一的 _id
字段存在,引用对象链接使用的实际值是该字段,除非另有说明。即使您需要像我为 BourbonResult
所做的那样在那里定义引用,您也可以这样做。
包含修改后的架构示例的完整列表:
var async = require('async'),
mongoose = require('mongoose'),
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 bourbonResultSchema = new Schema({
"_id": { "type": Schema.Types.ObjectId },
"avgRating": Number
});
var User = mongoose.model( "User", userSchema ),
Rating = mongoose.model( "Rating", ratingSchema ),
Bourbon = mongoose.model( "Bourbon", bourbonSchema ),
BourbonResult = mongoose.model(
"BourbonResult", bourbonResultSchema, null );
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) {
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) {
Rating.aggregate(
[
{ "$group": {
"_id": "$bourbonId",
"avgRating": { "$avg": { "$ifNull": ["$rating", 0 ] } }
}},
],
function(err,results) {
console.log(results);
results = results.map(function(result) {
return new BourbonResult(result);
});
Bourbon.populate(
results,
{ "path": "_id" },
function(err,results) {
console.log(results);
callback(err);
}
)
}
);
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
)
给出输出:
[ { _id: 54af7581efc755470845005c, avgRating: 6 } ]
[ { _id:
{ _id: 54af7581efc755470845005c,
name: 'test',
blog: 'test',
photo: 'test',
__v: 1,
ratings: [ 54af7581efc755470845005e, 54af7581efc755470845005f ] },
avgRating: 6 } ]
我在 angularjs 的前端有一个星级评级指令,我可以将评级保存到评级集合中。 这是我的评分模式/模型:
var mongoose = require('mongoose');
module.exports = mongoose.model('Rating', {
bourbonId: {type: mongoose.Schema.ObjectId, ref: 'Bourbon'},
userId: {type: mongoose.Schema.ObjectId, ref: 'User'},
rating: {type: Number, required: true},
ratingId : {type: mongoose.Schema.ObjectId}
});
这是我需要平均评分的项目:
'use strict';
var mongoose = require('mongoose'),
BourbonSchema = null;
module.exports = mongoose.model('Bourbon', {
BourbonId: {type: mongoose.Schema.ObjectId},
name: {type: String, required: true},
blog: {type: String, required: true},
photo: {type: String, required: true},
ratings: {type: mongoose.Schema.ObjectId, ref: 'Rating'},
rating: {type: Number}
});
var Bourbon = mongoose.model('Bourbon', BourbonSchema);
module.exports = Bourbon;
我需要找到一种通过波旁 ID 进行匹配的方法。从堆栈溢出来看,似乎使用聚合函数可能是可行的方法。 stack overflow link
这是我控制器中的当前损坏代码。我知道它还有很长的路要走,以及我使用 async.map 尝试解决此问题的失败尝试:
'use strict';
var Bourbon = require('../../../models/bourbon'),
Rating = require('../../../models/rating');
//async = require('async');
module.exports = {
description: 'Get Bourbons',
notes: 'Get Bourbons',
tags:['bourbons'],
handler: function(request, reply){
Bourbon.find(function(err, bourbons){
Bourbon.findOne(id, 'Rating', function(err, bourbon){
Rating.aggregate([
{$match: {bourbonId: {$in: bourbon.ratings}}},
{$group: {bourbonId: bourbon._id, average: {$avg: '$rating'}}}
], function(err, result){
bourbon.rating = result;
reply({bourbons:bourbons});
console.log('Bourbs', bourbons);
});
});
});
}
};
如有任何帮助,我们将不胜感激。把我的头撞在砖墙上,现在只是扔出随机代码。 ..
这是我实现的: 型号:
'use strict';
var mongoose = require('mongoose'),
BourbonResultSchema = null;
module.exports = mongoose.model('BourbonResult', {
_Id: {type: mongoose.Schema.ObjectId, 'ref': 'Bourbon'},
avgRating: {type: Number}
});
var BourbonResult = mongoose.model('BourbonResult', BourbonResultSchema, null);
module.exports = BourbonResult;
控制器:
'use strict';
var Bourbon = require('../../../models/bourbon'),
Rating = require('../../../models/rating'),
BourbonResult = require('../../../models/bourbonResult');
//async = require('async');
module.exports = {
description: 'Get Bourbons',
notes: 'Get Bourbons',
tags:['bourbons'],
handler: function(request, reply){
Rating.aggregate(
[
{'$group':{
'_id': '$bourbonId',
'avgRating': {'$avg': '$rating'}
}}
],
function(err,bourbons){
// Map plain results to mongoose document objects
bourbons = bourbons.map(function(result){
return new BourbonResult(result);
});
Bourbon.populate(bourbons,{'path': '_id'},function(err,bourbons){
reply({bourbons:bourbons});
console.log('BourbsRESSSSSS', JSON.stringify(bourbons, undefined, 2));
});
}
);
}
};
这是我从控制台日志返回的内容:
BourbsRESSSSSS [ { _id:
{ _id: 54acf382894ee2bcdebbc7f5,
name: 'example2',
photo: 'http://aries-wineny.com/wp-content/uploads/2014/09/woodford-reserve.jpg',
blog: 'example2',
__v: 0 },
avgRating: 3.3333333333333335 },
{ _id:
{ _id: 54a77e0fe63c850000f1269c,
name: 'example',
photo: 'http://aries-wineny.com/wp-content/uploads/2014/09/woodford-reserve.jpg',
blog: 'example',
__v: 0 },
avgRating: 3 } ]
============================================= ===========================
完美!
如果您要做的是在您的输出中列出每个 "Bourbon" 的 "average" 评级,可能有几种方法。但更简洁的方法之一是在表示聚合结果结构的特殊对象模型上使用 mongoose 填充。
除了 "bourbon" 之外,您在 "Ratings" 中似乎没有任何其他 "types",因此按理说您只想汇总整个集合。
// Set up a schema and model to match result structure
var bourbonResultSchema = new Schema({
"_id": { "type": Schema.Types.ObjectId, "ref": "Bourbon" },
"avgRating": Number
});
// The "null" for the collection is because there will not be any physical storage
var BourbonResult = mongoose.model( "BourbonResult", bourbonResultSchema, null );
// Aggregate an mapping code
Rating.aggregate(
[
{ "$group": {
"_id": "$bourbonId",
"avgRating": { "$avg": { "$ifNull": ["$rating",0 ] } }
}}
],
function(err,results) {
if (err) throw err;
// Map plain results to mongoose document objects
results = results.map(function(result) {
return new BourbonResult(result);
});
Bourbon.populate(results,{ "path": "_id" },function(err,results) {
if (err) throw err;
reply(results);
console.log( JSON.stringify( results, undefined, 2 ) );
})
}
);
因此,您定义了一个架构和模型,该架构和模型将匹配return聚合结果的结构。这样做是为了稍后您可以调用 .populate()
。
return聚合的结果不是 mongoose 文档,而是普通对象。然后,通过 .map()
方法将所有结果传递给 BourbonResult
对象,以便 return 一个 BourbonResult
.
由于这些不是 mongoose 文档,您可以调用 .populate()
的模型方法,该方法将 mongoose 文档数组作为第一个参数。第二个 "options" 参数告诉方法将哪个字段路径用于填充,即前面定义的 _id
以引用 Bourbon
模型。
在 .populate()
的回调中,returned 结果合并了聚合的平均得分 return 和 [=18= 中的完整 Bourbon
对象] 场地。如果您真的愿意,您还可以 运行 在每个 Bourbon
对象上进一步 .populate()
语句,以便引入它的任何引用。有点复杂但可能。
请注意,"Bourbon" 模型中的 "bourbonId" 字段可能有点多余。 MongoDB 总是有一个唯一的 _id
字段存在,引用对象链接使用的实际值是该字段,除非另有说明。即使您需要像我为 BourbonResult
所做的那样在那里定义引用,您也可以这样做。
包含修改后的架构示例的完整列表:
var async = require('async'),
mongoose = require('mongoose'),
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 bourbonResultSchema = new Schema({
"_id": { "type": Schema.Types.ObjectId },
"avgRating": Number
});
var User = mongoose.model( "User", userSchema ),
Rating = mongoose.model( "Rating", ratingSchema ),
Bourbon = mongoose.model( "Bourbon", bourbonSchema ),
BourbonResult = mongoose.model(
"BourbonResult", bourbonResultSchema, null );
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) {
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) {
Rating.aggregate(
[
{ "$group": {
"_id": "$bourbonId",
"avgRating": { "$avg": { "$ifNull": ["$rating", 0 ] } }
}},
],
function(err,results) {
console.log(results);
results = results.map(function(result) {
return new BourbonResult(result);
});
Bourbon.populate(
results,
{ "path": "_id" },
function(err,results) {
console.log(results);
callback(err);
}
)
}
);
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
)
给出输出:
[ { _id: 54af7581efc755470845005c, avgRating: 6 } ]
[ { _id:
{ _id: 54af7581efc755470845005c,
name: 'test',
blog: 'test',
photo: 'test',
__v: 1,
ratings: [ 54af7581efc755470845005e, 54af7581efc755470845005f ] },
avgRating: 6 } ]