Mongoose: Populating with projection using attribute of scheme - node.js

I triying the following population/projection and work fine
modelBaby.findOne({'userId': req.user.data._id, '_id': req.params.id})
.populate('categories._categoryId', {
levels:{
$elemMatch:{
name: 'PURPLE'
}
}
})
But i need name as a variable something like:
modelBaby.findOne({'userId': req.user.data._id, '_id': req.params.id})
.populate('categories._categoryId', {
levels:{
$elemMatch:{
// over heree !!
name: 'categories._levelName' or this._levelName
}
}
})
the scheme ref is
const babyCategory = new mongoose.Schema(
{
answer: {type: String},
_categoryId: {type: Schema.Types.ObjectId, required: true, ref: 'category'},
_categoryName: {type: String, required: true},
_levelName: {type: String, required: true}
},
{versionKey: false, _id : false}
);

Related

How to properly select document via populate from another document with mongoose?

I did a select with populate and it works, but feel like there is a better way.
My models:
const DeviceSchema = new Schema({
name: String,
MAC: {type: String, unique: true, required: true, dropUps: true},
serialNumber: {type: String, unique: true, dropUps: true},
date: {type: Date, default: Date.now},
})
const UserSchema = new Schema({
created: {type: Date, default: Date.now},
})
const OrganisationSchema = new Schema({
name: {type: String, required: true},
members: [{type: ObjectId, ref: 'User'}],
devices: [{type: ObjectId, ref: 'Device'}],
created: {type: Date, default: Date.now},
})
Users and Devices may belong to multiple Organisations.
Through Organisation the User may obtain access to the Devices.
The code I seek to optimize:
const devicesSerial = await Organisation.find()
.where('members')
.equals(req.user.id)
.populate('devices', 'MAC')
.then((orgs) => {
console.log('orgs', orgs)
return _.flatMap(
orgs.map((org) => org.devices.map((device) => device.MAC))
)
})
const events = await SensorEvent.aggregate([
{$match: {MAC: {$in: devicesSerial}}},
{$sort: {date: 1}},
{
$group: {
_id: '$MAC',
temperature: {$last: '$temperature'},
humidity: {$last: '$humidity'},
weight: {$last: '$weight'},
theId: {$last: '$_id'},
date: {$last: '$date'},
},
},
])

How to add value inside an array of array in mongoose by value find by ID?

I want to add the data inside the order products_id array
I tried to push the array by find it by user id and then add push it inside the products_id but i won't able to add the data.
User.findById(user_id,(err,user)=>{
if(err) throw err;
const lastOrderId = user.order.slice(-1)[0]._id
//console.log(cb.order.slice(-1)[0]._id);
User.update({'order[0]._id': lastOrderId}, {$push: {'order.0.$.products_id': 123}},{safe:true,upsert:true})
/*User.findOneAndUpdate({'_id' : user_id, 'order._id': lastOrderId}
,{$push: [{'order[0].products_id': [123123]}]},{safe:true,upsert:true})*/
})
My User Schema
const userSchema = mongoose.Schema({
_id: mongoose.Types.ObjectId,
user_name: {type:String,require: true},
email: {type:String, require: true},
password: {type:String,require:true},
full_name: {type:String},
order: [{
_id: mongoose.Types.ObjectId,
products_id: [],
date: {
type: Date,
default: Date.now
}
}]
})
After updating i want
const userSchema = mongoose.Schema({
_id: mongoose.Types.ObjectId,
user_name: {type:String,require: true},
email: {type:String, require: true},
password: {type:String,require:true},
full_name: {type:String},
order: [{
_id: mongoose.Types.ObjectId,
products_id: [5d5d7a7ea0c4aaf6212993ec, 5d627a962a5c637e7a0d5d1c, 5d627a49fa24ba7d15451afb],
date: {
type: Date,
default: Date.now
}
}]
})
You can use arrayFilter for this.You can do it like this.
User.update({user_id},{$set: { 'order.$[ord]': lastOrderId },
$push: {'order.$[ord].products.$[prd]':123}
}, {
arrayFilters: [{'_id': user_id}]
})

How do I use nested schemas in mongoose, using 'type', to create arrays?

I am trying to create a nested mongoose schema that uses 'type' to create a nested array.
The schema that I think I am having an issue with is "chorePerson".
Here is the data that I am trying to put into a schema:
{
"chart": [
{
"ordinal": 0,
"chorePerson": [
{
"person": "emily",
"chore": "Catbox"
},
{
"person": "Steve",
"chore": "Dishes"
}
]
}
]
Here is my current schema. Note the use of "type" for "chart" and "chorePerson"
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const chorePersonSchema = new mongoose.Schema({
person: {type: String, requried: true},
chore: {type: String, required: true},
});
const chartSchema = new mongoose.Schema({
ordinal: {type: Number, required: true},
chorePerson:{ type: chorePersonSchema },
});
// create the schema
const ChoreChartSchema = new Schema({
affiliation: {type: String, required: true},
currentWeekNumber: {type: Number, required: true},
currentYear: {type: Number, required: true},
chart:{ type: chartSchema },
date: {type: Date, default: Date.now},
})
module.exports = ChoreChart = mongoose.model('cm_chorechart', ChoreChartSchema)
When I run my code this is what I get before the crash:
{ _id: 5c742ed116a095522c38ddfc,
affiliation: 'family',
currentYear: 2019,
currentWeekNumber: 9,
date: 2019-02-25T20:26:33.914Z,
chart: [ { ordinal: 0, chorePerson: [Array] } ] }
I think... chorePerson is causing the error... but I don't know how to fix it.
Here is the exception:
(node:6728) UnhandledPromiseRejectionWarning: ObjectExpectedError: Tried to set nested object field `chart` to primitive value `[object Object]` and strict mode is set to throw.
What I have tried
I tried this schema:
const chartSchema = new mongoose.Schema({
ordinal: {type: Number, required: true},
chorePerson : [{
person : String,
chore : String
}]
});
Update:
OK... so I went back to basics and this works, but it's not how I want the final schema to be. Can anybody help out with nesting this ?
// create the schema
const ChoreChartSchema = new Schema({
affiliation: {type: String, required: true},
currentWeekNumber: {type: Number, required: true},
currentYear: {type: Number, required: true},
// chart:{ type: chartSchema },
chart:[{
ordinal: 0,
chorePerson : [{
person : String,
chore : String
}]
}],
date: {type: Date, default: Date.now},
})
Turns out it was easier than I thought:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const chorePersonSchema = new mongoose.Schema({
person: {type: String, requried: true},
personID: {type: String, required: true},
chore: {type: String, required: true},
choreID: {type: String, required: true},
});
const chartSchema = new mongoose.Schema({
ordinal: {type: Number, required: true},
chorePerson : [{ type:chorePersonSchema }]
});
// create the schema
const ChoreChartSchema = new Schema({
affiliation: {type: String, required: true},
weekNumber: {type: Number, required: true},
year: {type: Number, required: true},
chart:[{type: chartSchema}],
date: {type: Date, default: Date.now},
})
module.exports = ChoreChart = mongoose.model('cm_chorechart', ChoreChartSchema)

Mongoose Populate Not Working For Me

I have this schema for users:
var mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
mongoose.Promise = global.Promise;
var userSchema = new mongoose.Schema ({
username: {type: String, required: true, unique: true},
password: {type: String},
role: {type: String, required: true},
confirmed: {type: Boolean, required: true, default: false},
active: {type: Boolean, required: true, default: true},
name: String,
created: {type: Date, default: Date.now},
admin: {type: Boolean, default: false, required: true}
});
userSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", userSchema);
And another schema for companies, where clients refer to an array of users:
var mongoose = require("mongoose");
mongoose.Promise = global.Promise;
var companySchema = new mongoose.Schema ({
name: {type: String, required: true, unique: true},
created: {type: Date, default: Date.now},
active: {type: Boolean, required: true, default: true},
staff: [{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}],
clients: [{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}]
});
module.exports = mongoose.model("Company", companySchema);
I have the below code in my route, but the user information is not being populated into the company object, what am I doing wrong?
// EDIT route
router.get("/:company_id/edit", middleware.checkCompanyOwnership, function(req, res) {
Company.findOne({_id: req.params.company_id}).populate({path: 'clients'}).exec(function(err, company) {
if (err || !company) {
console.log(err);
req.flash("error", err.message);
res.redirect("/");
} else {
console.log("Request to edit company.");
//console.log(company);
res.render("company/edit", {title: "Edit Company", company: company});
}
});
});
This is what I am getting if I console log company:
{ _id: 5a070874b4292914444b6e06,
name: 'ABC',
__v: 1,
clients:
[ { username: 'abcdefg#gmail.com',
_id: 5a070206616810129b5c876a } ],
staff: [],
active: true,
created: 2017-11-11T14:25:56.359Z }
Thanks for your help.
Your company schema should look like this
var companySchema = new mongoose.Schema ({
...
staff: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
clients: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }]
});
See the docs http://mongoosejs.com/docs/populate.html

Schema Association in Mongoose

I have 2 models:
Here is the User Model:
const userSchema = new mongoose.Schema({
email: { type: String, unique: true, required: true },
password: { type: String, required: true },
passwordResetToken: String,
passwordResetExpires: Date,
facebook: String,
twitter: String,
tokens: Array,
profile: {
name: String,
gender: String,
location: String,
website: String,
picture: String
}
}, { timestamps: true });
And here is the Revive Model:
const reviveSchema = new mongoose.Schema({
reviveShowName: {type: String, required: true},
reviveTitle: {type: String, required: true},
reviveCategory: {type: String, required: true},
reviveGoal: {type: Number, required: true},
revivePhoto: {type: String, required: true},
reviveVideo: {type: String},
reviveStory: {type: String},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
name: String
}
}, { timestamps: true });
In the Revive model, I'm trying to the reference the author and get the author's id and that works... How do I also get the name from profiles -> name...? Clearly name: String is wrong...
Mongoose relations work, based on the ref and type value of the nested object. In your case you have associated the id property of author to point to the User model.
If you want to populate the author with the user information, you should just do :
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
Then in your query you just use populate
Revive.find({})
.populate( 'author' )
.exec( function( error, docs ) {
console.log( docs ); // will have `[{author:{profile:{...}}}]` data
} );

Resources