Mongoose Populate Empty Array - node.js

const Schema = mongoose.Schema
const logEntry = new Schema({
no:{
type: Number
},
type: {
type: String
},
createdAt: {
type: Date,
default: Date.new
},
ingredients: {
type: String
},
process: {
type: String
},
cook: [{
type: mongoose.Schema.Types.ObjectId, ref: 'shef'
}]
});
const shefEntry = new Schema({
name: {
type: String
},
dish: {
type: mongoose.Schema.Types.ObjectId, ref: 'logDetails'
}
})
const foodItem = mongoose.model('logDetails', logEntry);
const Cook = mongoose.model('shef', shefEntry);
This is my Schema.
app.route('/log_entries')
.get(controller.index)
.post(controller.create)
This is my route.
exports.index = function(req, res){
logEntry.find({})
.populate('Cook')
.exec(function(err, logEntry){
if(err) res.send(err);
res.json(logEntry);
})
}
This is my controller where I'm trying to populate. My requirement is to populate the name of cook into recipe collection but I get the result as
{
"cook": [],
"_id": "5dafdbd8b9cefa2670ab73c7",
"no": 101,
"type": "Non-Veg",
"ingredients": "Gobi,Paneer",
"process": "Go on with the manual",
"__v": 0
},
{
"cook": [],
"_id": "5dbb76bf5356143124d3afbd",
"no": 101,
"type": "veg",
"ingredients": "Gobi,Paneer",
"process": "Go on with the manual",
"__v": 0
}
Can anyone explain how to use mongoose populate? I mean about how to join 2 collections and which collection to make main collection. Also refer me with some good website where I can learn more about mongoose join.

Cook replace with cook
exports.index = function(req, res){
logEntry.find({})
.populate('cook')
.exec(function(err, logEntry){
if(err) res.send(err);
res.json(logEntry);
}) }

Related

Problem with the relationship in express/mongoose

Im creating a document named 'Sells', each sell has properties such as date, name, total, the id of the user who created it ect. and I have another document named 'Sell_details' where I store the details of each sell with their sell _id. So how do i retrieve all the sells i have in the database with an array of the details which that sell has? I've tried to do it but it doesn't retrieve all the details and among other problems. Here's what i have.
this is the sell model
const mongoose = require('mongoose');
const validator = require('validator');
const uniqueValidator = require('mongoose-unique-validator');
const ventaSchema = new mongoose.Schema({
usuarioId: {
type: mongoose.Schema.Types.ObjectId,
required: true
},
clienteId: {
type: mongoose.Schema.Types.ObjectId,
required: true
},
tipo_comprobante: {
type: String,
required: true
},
num_comprobante: {
type: Number,
required: true
},
serie_comprobante: {
type: Number,
required: true
},
fecha: {
type: Date,
default: Date.now()
},
impuesto: {
type: Number,
required: true
},
total: {
type: Number,
required: true
},
estado: {
type: String,
default: 'Activo'
},
owner: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
ventas: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Detalle_Venta'
},
detalles: {
type: Array
}
},{ toJSON: { virtuals: true } });
ventaSchema.plugin(uniqueValidator, { message: 'Expected {PATH} to be unique' });
const Venta = mongoose.model('Venta', ventaSchema);
module.exports = Venta;
his is the sell router:
router.get('/ventas', auth, async(req, res) => {
try {
await req.user.populate({
path: 'ventas',
options: {
limit: req.query.limit
}
}).execPopulate();
req.user.ventas.forEach(element => {
const detalles = Detalle_Venta.find({ventaId: element._id});
detalles.then(el => {
el.forEach(detalle => {
if (element.detalles.length > 1) {
element.detalles.forEach(el => {
const isAdded = el._id === detalle._id;
if (isAdded) {
element.detalles.push(detalle);
}
})
} else {
element.detalles.push(detalle);
}
});
});
element.save();
});
res.send(req.user.ventas);
} catch (error) {
res.status(400).send(error);
}
});
and this is the output from postman:
[
{
"fecha": "2020-06-22T18:16:44.175Z",
"estado": "Activo",
"detalles": [
{
"_id": "5ef0fa4e49de0641c46eca0b",
"idArticulo": "5ee825bfb3da101df49822ae",
"cantidad": 30,
"precio": 2,
"descuento": 0,
"ventaId": "5ef0fa4e49de0641c46eca0a",
"__v": 0
},
{
"_id": "5ef0fa4e49de0641c46eca0b",
"idArticulo": "5ee825bfb3da101df49822ae",
"cantidad": 30,
"precio": 2,
"descuento": 0,
"ventaId": "5ef0fa4e49de0641c46eca0a",
"__v": 0
}
],
"_id": "5ef0fa4e49de0641c46eca0a",
"usuarioId": "5ee3b6b50376d7143c476834",
"clienteId": "5ee6b115e43839274cc50ddb",
"tipo_comprobante": "RNC",
"num_comprobante": 1000000,
"serie_comprobante": 20001,
"impuesto": 18,
"total": 10500,
"owner": "5ef0e64083f8c815cc67cd7c",
"__v": 2,
"id": "5ef0fa4e49de0641c46eca0a"
},
{
"fecha": "2020-06-22T18:16:44.175Z",
"estado": "Activo",
"detalles": [
{
"_id": "5ef0fa5a49de0641c46eca0d",
"idArticulo": "5ee825bfb3da101df49822ae",
"cantidad": 30,
"precio": 2,
"descuento": 0,
"ventaId": "5ef0fa5a49de0641c46eca0c",
"__v": 0
},
{
"_id": "5ef0fa5a49de0641c46eca0e",
"idArticulo": "5ee825bfb3da101df49822ae",
"cantidad": 303,
"precio": 2,
"descuento": 0,
"ventaId": "5ef0fa5a49de0641c46eca0c",
"__v": 0
}
],
"_id": "5ef0fa5a49de0641c46eca0c",
"usuarioId": "5ee3b6b50376d7143c476834",
"clienteId": "5ee6b115e43839274cc50ddb",
"tipo_comprobante": "RNC",
"num_comprobante": 1000000,
"serie_comprobante": 20001,
"impuesto": 18,
"total": 10500,
"owner": "5ef0e64083f8c815cc67cd7c",
"__v": 1,
"id": "5ef0fa5a49de0641c46eca0c"
}
]
Before you say i did it, the first array of the 'detalles' array (which stores the sell details of that sell), i added one sell detail and i'm getting two, and the second array of the other sell, i'm getting two sell details but i added 3 and if i add 4 i'm only getting 2 and i don't know why. is there a way to fix it and another best way to do it ?
mongoose has a powerful aggregation operator called populate which you have used.
You should use type ObjectId to the property sell details.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
Then you create the author and story linking them up
const author = new Person({
_id: new mongoose.Types.ObjectId(),
name: 'Ian Fleming',
age: 50
});
author.save(function (err) {
if (err) return handleError(err);
const story1 = new Story({
title: 'Casino Royale',
author: author._id // assign the _id from the person
});
story1.save(function (err) {
if (err) return handleError(err);
// that's it!
});
});
You can thereafter populate
Story.
findOne({ title: 'Casino Royale' }).
populate('author').
exec(function (err, story) {
if (err) return handleError(err);
console.log('The author is %s', story.author.name);
// prints "The author is Ian Fleming"
});
This will ensure you don't get an entry twice..

I am trying to populate the **task_item** you can see below but I am not getting the result. Nodejs, Expressjs and MongoDb

I am trying to populate the task_item you can see below but I am not getting the result.
{
"msg": "User not exists",
"cart": {
"_id": "5ec0c28cf494113aa06c99d9",
"task_items": [
{
"quantity": 1,
"_id": "5ec0c28cf494113aa06c99da",
**"task_item": "5ebe499d7e657d322c39345f"**
},
{
"quantity": 1,
"_id": "5ec0d018ecc2411cf40bceae",
**"task_item": "5ebe499d7e657d322c39345f"**
},
{
"quantity": 1,
"_id": "5ec0d4abfac25246689d15a7",
**"task_item": "5ec0d4a2fac25246689d15a6"**
}
],
"crreated": "2020-05-17T04:50:20.869Z",
"user": {
"_id": "5ebe4d5d440ab504c8a0d128",
"name": "Ajit",
"phone": "9668854799",
"avatar": "//www.gravatar.com/avatar/20c3d59b7049c9ad85cd33e2ebd3151c?s=200&r=pg&d=mm",
"password": "$2a$10$FdH7QzoqOHnVoLbbm9GaUOLaJbTTqPWzFWeFACkea2NWlrJrFxZ5a",
"createdAt": "2020-05-15T08:05:49.418Z",
"__v": 0
},
"__v": 2
}
}
Below is the Cart.js Model
const monngose = require('mongoose');
const Schema = monngose.Schema;
const CartSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
task_items: [{
task_item: {type:Schema.Types.ObjectId, ref: 'SubTaskCategoryItem'},
quantity: { type: Number, default: 1 }
}],
totalPrice: {
type: Number
},
item: {
type: Schema.Types.ObjectId,
ref: 'SubTaskCategoryItem'
},
crreated: {
type: Date,
default: Date.now
}
});
module.exports = monngose.model('Cart', CartSchema);
SubCategoryItem.js - This is the item model
const mongoose = require('mongoose');
const SubTaskItemSchema = new mongoose.Schema({
subtaskItemName: {
type: String,
required: true,
unique: true,
trim: true
},
subtaskItemImage: {
type: String
},
subtaskItemTime: {
type: String
},
description: {
type: String,
trim: true
},
subtaskItemPrice: {
type: String
},
subtaskItemStatus: {
type: Boolean,
default: true
},
subtask: {
type: mongoose.Schema.ObjectId,
ref: 'SubTask',
required: true
},
createdAT: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model("SubTaskCategoryItem", SubTaskItemSchema);
Here I am trying to populate - cart.js router
const express = require('express');
const Cart = require('../../models/admin/Cart');
const checkJwt = require('../../middleware/admin/user_auth');
const TaskItem = require('../../models/admin/SubTaskCategoryItem');
const router = express.Router();
router.post('/add_cart', checkJwt, (req, res, next) => {
const product_id = req.query.productId;
const quantity = req.query.quantity;
const user = req.user.id;
router.get('/get_cart', checkJwt, (req, res, next) => {
Cart.findOne({ user: req.user.id })
.populate({
path: 'user'
})
.populate({
path: 'item'
})
.exec((err, cart) => {
res.json({
msg: 'User not exists',
cart: cart
});
})
})
module.exports = router;
I am trying to populate the task_item but I am not able to do. If anyone knows please see this code.

Post insert multiple data using express js and mongodb

im trying to insert data in mongodb using express in the format as below which im not able to achieve.
I need to enter multiple product and serial no in the data field. please help!
[
{
"_id": "5cbabbd7545ac20f7c912e6a",
"refno1": "REF1",
"refno2": "REF2",
"prodregdate": "2019-04-09T00:00:00.000Z",
"data": [
{
"_id": "5cbabbd7545ac20f7c912e6b",
"product": "5cb86b45cfafaa1860e29b2a",
"serialno": "s123"
},
{ // this data im not able to enter how to do it
"_id": "5cbabbd7545ac20f7c912e6b",
"product": "5cb86b45cfafaa1860e29b2a",
"serialno": "s123"
},
],
"customer": {
"_id": "5c98bb0a42207b16d8fbd3cf",
"customername": "Raghav Update"
},
"customertype": {
"_id": "5c7a1a1d4913fa08ac75c027",
"customertype": "Government "
},
"__v": 0
}
]
// My Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ProductRegistrationSchema = new Schema({
//Product Details
_id: { type: mongoose.Schema.Types.ObjectId },
refno1: { type: String },
refno2: { type: String },
data: [{
product: {
type: mongoose.Schema.Types.ObjectId,
ref: "product"
},
//DATES
//OEM
oemwarrantyfrom: { type: Date },
oemwarrantyto: { type: Date },
//SERVICE PROVIDER
warrantyfrom: { type: Date },
warrantyto: { type: Date },
serialno: { type: String },
}],
prodregdate: { type: Date },
//Details of Customer buying the product
customer: {
type: mongoose.Schema.Types.ObjectId,
ref: "customer"
},
customertype: {
type: mongoose.Schema.Types.ObjectId,
ref: "customertype"
},
department: {
type: mongoose.Schema.Types.ObjectId,
ref: "customersubdepartment"
},
remarks: { type: String },
entrydate: {
type: Date,
dafault: Date.now
}
module.exports = ProductRegistration = mongoose.model('productregistration', ProductRegistrationSchema);
// My Routes just for add
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const Product = require("../../../models/Master/Products");
//importing the model of ProductRegistrationSchema
const ProdReg = require('../../../models/Entries/ProductRegistration');
//Creating a new ProductRegistration Data
router.post('/add', (req, res)=>{
const newProdReg = new ProdReg({
_id: new mongoose.Types.ObjectId(),
refno1: req.body.refno1,
refno2: req.body.refno2,
prodregdate: req.body.prodregdate,
data: {
product: req.body.productid,
oemwarrantyfrom: req.body.oemwarrantyfrom,
oemwarrantyto: req.body.oemwarrantyto,
warrantyfrom: req.body.warrantyfrom,
warrantyto: req.body.warrantyto,
serialno: req.body.serialno,
},
customer: req.body.customerid,
customertype: req.body.customertypeid,
department: req.body.customersubdepartmentid,
remarks: req.body.remarks
// deliverydate: req.body.deliverydate,
// address: req.body.address,
// assignedto: req.body.employeesid,
// warrantyprovider: req.body.serviceproviderid,
// oemwarrantyprovider: req.body.oemcompanyid,
// warrantystartdate: req.body.warrantystartdate,
// warrantyexpiredate: req.body.warrantyexpiredate,
});
newProdReg.save().then(prodreg => res.json(prodreg));
});
im not able to enter 2 product and serial no in the data field. One one is getting entered.
Firstly make your request JSON in the proper format if you want to insert two products which you are getting from request data.
For example, your request JSON should be in the flowing format:
{"refno1":"x", "refno2": "y", "prodregdate": "2019-04-19T18:30:00.000Z","data": [{"product": "product_1_object_id","oemwarrantyfrom":"2019-04-19T18:30:00.000Z", "oemwarrantyto": "2019-04-19T18:30:00.000Z","warrantyfrom":"2019-04-19T18:30:00.000Z", "warrantyto":"2019-04-19T18:30:00.000Z","serialno":"123" },{"product": "product_2_object_id","oemwarrantyfrom":"", "oemwarrantyto": "2019-04-19T18:30:00.000Z","warrantyfrom":"2019-04-19T18:30:00.000Z", "warrantyto":"2019-04-19T18:30:00.000Z","serialno":"456" }],"customersubdepartmentid":"departement_object_id","customerid":"customer_object_id","customertypeid":"customer_type_object_id","remarks":"anything"}
If you are using POSTMAN then you can try this JSON in the "raw" option.
Then in your code, it should be like below:
router.post('/add', (req, res)=>{
const newProdReg = new ProdReg({
_id: new mongoose.Types.ObjectId(),
refno1: req.body.refno1,
refno2: req.body.refno2,
prodregdate: req.body.prodregdate,
data: req.body.data, // This will be type array with two products details
customer: req.body.customerid,
customertype: req.body.customertypeid,
department: req.body.customersubdepartmentid,
remarks: req.body.remarks
});
newProdReg.save().then(prodreg => res.json(prodreg));
});
Please match your request param with JSON I took it from your schema.

Trying to populate an object inside another object that is inside another object (NODE.JS)

This function gets a specific "process" and shows the following information in json: (POSTMAN)
{
"process": {
"_id": "5c18e8d1d4817811839d43d2",
"name": "Dyeing",
"colour": {
"_id": "5c18c972b39bb20769288e8f",
"name": "azul",
"category": "5c18c09f4c6baf05ea621bca",
"__v": 0
},
"__v": 0
},
"request": {
"type": "GET",
"url": "http://localhost:3000/process"
}
}
Process controller function
exports.process_get_process = (req, res, next) => {
Process.findById(req.params.processId)
.populate("colour")
.populate("category")
.exec()
.then(process => {
if (!process) {
return res.status(404).json({
message: "Process not found"
});
}
res.status(200).json({
process: process,
request: {
type: "GET",
url: "http://localhost:3000/process"
}
});
})
.catch(err => {
res.status(500).json({
error: err
});
});
};
The model for the "process" is the following schema:
const mongoose = require('mongoose');
const processSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
price: { type: Number, required: false },
colour: { type: mongoose.Schema.Types.ObjectId, ref: 'Colour', required: false },
});
module.exports = mongoose.model('Process', processSchema);
This is the Colour model:
As you can see the object "category" is inside "colour" and i want to show him in the "process" object as well.
const mongoose = require('mongoose');
const colourSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
category: { type: mongoose.Schema.Types.ObjectId, ref: 'Category', required: true },
});
module.exports = mongoose.model('Colour', colourSchema);
Problem: Inside the "colour" exist a "category" object, but only shows the category id, and i want him to show all the category information. How can I populate it?
You can specify that as options for the populate function.
Process.findById(req.params.processId)
.populate({
path: 'colour',
populate: { path: 'category' }
})
.exec()

How to get a rating average in Mongoose / node

I have a star rating directive working on the front end for angularjs, I can save a rating to the rating collection.
here is my rating schema / model:
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}
});
Here is the item that I need an average rating for:
'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;
I need to find a way to match by bourbon ID. From looking at stack overflow, it seems using an aggregate function may be the way to go. stack overflow link
Here is the current broken code I have in my controller. I know it's way off, along with failed attempts that i've had using async.map to try and solve this as well:
'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);
});
});
});
}
};
any help would be much appreciated. Beating my head against a brick wall, just throwing random code out now. ..
here's what i've implemented:
model:
'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;
controller:
'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));
});
}
);
}
};
here's what I get back from the consolelog:
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 } ]
========================================================================
Perfect!
If what you are trying to do is list the "average" rating against each "Bourbon" here in your output there are probably a couple of approaches. But one of the cleaner ways would be to utilize mongoose populate on a special object model representing the structure of the results from aggregation.
You don't appearhave any other "types" of "Ratings" here other than for "bourbon", so it stands to reason that you just want to aggregate the whole collection.
// 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 ) );
})
}
);
So you define a schema and model that will match the structure of the results returned from aggregate. This is done so you can call .populate() later.
The results returned from aggregate are not mongoose documents, but just plain objects. You then cast all the results to BourbonResult objects by passing them through the .map() method in order to return an array of BourbonResult.
Since these are not mongoose documents, you can call the model method of .populate(), which takes an array of mongoose documents as the first argument. The second "options" argument tells the method which field path to use for the popluation, which is _id as defined earlier to reference the Bourbon model.
In the callback to .populate() the returned results merge both the average score returned from aggregation and the complete Bourbon object within the _id field. If you really wished, you could also run further .populate() statements over each Bourbon object in order to pull in any of it's references. A bit more complicated but possible.
As a note, the "bourbonId" field in the "Bourbon" model is probably a bit redundant. MongoDB always has a unique _id field present and the actual value used by referenced object links is that field unless specified otherwise. Even if you needed to define a reference there as I have done for BourbonResult then you can do that as well.
A complete listing with amended schema examples:
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();
}
)
Gives output:
[ { _id: 54af7581efc755470845005c, avgRating: 6 } ]
[ { _id:
{ _id: 54af7581efc755470845005c,
name: 'test',
blog: 'test',
photo: 'test',
__v: 1,
ratings: [ 54af7581efc755470845005e, 54af7581efc755470845005f ] },
avgRating: 6 } ]

Resources