Updating a subdoc array in Mongoose without getting the parent - javascript

Schema:
var viewSchema = new Schema({
active: Boolean
, path: String
})
var pageSchema = new Schema({
name: String
, desc: String
, url: String
, views: [viewSchema]
})
In order to add a new view to an existing page I am doing:
Page
.findOne({ id: pageId })
.exec(function (err, page) {
page.views.push({ path: path })
page.save(function(err) {
//saved
})
})
Is there a way to do the same without actually getting the page?
Page.update({ id: pageId }
, { SOMETHING }
, function(err){
//updated
})

It works..
Page.update({ _id: page.id},{ $push: { "views": { path: "#page", active: true } } })
thanks #Alistair-Nelson

Related

i can't populate mongoose deep subdocument

Below is the code that simplified the model and schema I'm having a hard time with
const guildSchema = new Schema<Guild>({
sheets: [sheetSchema],
crews: [crewSchema],
});
const GuildModel= getModel('Guild', guildSchema)
const sheetSchema = new Schema<Sheet>({
deales: [dealSchema]
})
const SheetModel = getModel('Guild.sheets', sheetSchema)
const dealSchema = new Schema<Deal>({
crew: [{ type: Schema.Types.ObjectId, refPath: 'Guild.crews' }],
damage: { type: Number, required: true },
})
const DealModel = getModel('Guild.sheets.deales', dealSchema)
const crewSchema = new Schema<Crew>({
name: { type: String, required: true },
})
const CrewModel= getModel('Guild.crews', crewSchema)
and this is Mocha-chai testcode what always throw exception
it("populated guild.sheets.deales.boss must have name",async () => {
const guild = await GuildModel.findOne({})
await guild.populate({
path: 'sheets.deales.crew'
}).execPopulate()
expect(guild.sheets[0].deales[0].crew).to.has.property("name") // expected [] to have property 'name'
})
None of the answers on stackoverflow solved my problem. I wasted 5 hours on just a few lines of this code. please help me
You checked this? https://github.com/Automattic/mongoose/issues/1377#issuecomment-15911192
This person changed nested code
var opts = {
path: 'author.phone',
select: 'name'
};
BlogPost.populate(docs, opts, function (err, docs) {
assert.ifError(err);
docs.forEach(function (doc) {
console.log(doc);
});
callback(null);
from this
var authors = docs.map(function(doc) {
return doc.author;
});
User.populate(authors, {
path: 'phone',
select: 'name'
}, callback);
to this.
author(User)is in BlogPost. BlogPost Schema has just User ObjectId, so can't understand author.phone
I might have already checked it, but I'm uploading it just in case.

Dynamic query in mongo and NodeJs asking for fields of documents embedded?

I am trying to make a dynamic query based on multiple selection of the user.
In my application I have the Publication schema that has the Pet schema embedded as follows:
var status = ["public", "private", "deleted"];
var publication_schema = new Schema({
pet:{
type: Schema.Types.ObjectId,
ref: "Pet"
},
status: {
type: String,
enum: status,
default: status[0]
}
});
module.exports = mongoose.model('Publication', publication_schema);
var pet_schema = new Schema({
type: {
type: String,
require: true
},
createdDate: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Pet', pet_schema);
Insyde an async method I build the query, getting all the user input values from the object filter, also I have the query object where I push the different criteria and use it with an $and
let query = {};
let contentQuery = []
if (filter.public && !filter.private) {
contentQuery.push({ status: { $eq: "public" } });
} else if (filter.privada && !filter.public) {
contentQuery.push({ status: { $eq: "private" } });
}
query = { $and: contentQuery }
try {
const publication = await Publication.find(query).populate('pet');
} catch (e) {
console.log(e)
}
the problem is when I want to add more criteria such as follows:
if (filter.specie) { // for example filter.specie equals 'cat'
contentQuery.push({ pet: { type: { $eq: filter.specie } } });
}
I get the error:
'Cast to ObjectId failed for value "{ type: { \'$eq\': \'cat\' } }" at path "pet" for model "Publication"',
name: 'CastError',
stringValue: '"{ type: { \'$eq\': \'cat\' } }"',
kind: 'ObjectId',
value: { type: { '$eq': 'cat' } },
path: 'pet',
reason: undefined,
model: Model { Publication } }
So. How can I do to query the fields of publication and also the pet fields inside publication?
You can have a look on Populate Query Conditions
Instead of .populate('pet') you could do something like
Publication.find({})
.populate({
path: 'pet',
match: { specie: 'cat'},
// You can select the fields you want from pet, or remove the select attribute to select all
select: 'name -_id',
// Here you could add options (e.g. limit)
options: { limit: 5 }
}).exec();
The above query will get you all Publications with pet.specie equals to 'cat'

Mongoose: deep population

I have Patient model contains ref to Path :
const PatientSchema = Schema({
idPatient: Schema.Types.ObjectId,
firstName: String,
lastName: String,
path: {type: Schema.Types.ObjectId, ref: 'Path'}
});
Path model with array of ref to Zone:
const PathSchema = connection.mongoose.Schema({
zones: [{
type: connection.mongoose.Schema.Types.ObjectId,
ref: 'Zone'
}],
});
and finally Zone model:
const ZoneSchema = connection.mongoose.Schema({
name: String,
duration: Number,
});
I'm trying to get all the patient with their path and the zones for each path inside patient:
Here an example of data with a simple populate on the patient:
[
{
"_id": "5d00b7dab927301ad392e6e4",
"idPatient": "5d00b7dab927301ad392e6e5",
"firstName": "Amine",
"lastName": "Harbaoui",
"path": {
"_id": "5d010263b927301ad392e6ea",
"zones": [
"5d010c72b927301ad392e6eb",
"5d010cf7b927301ad392e6ec"
]
}
}
]
And here how I tried to get what I want:
Patient.find()
.lean()
.populate('path')
.exec((error, patients) => {
if (error) {
console.log(error);
} else {
const zones = patients.map(p => p.path.zones);
Path.populate(zones, {
path: 'zones'
}, (error, data) => {
if (error) {
console.log(error);
} else {
console.log(data);
}
})
}
})
But here's the exception I get:
{ MissingSchemaError: Schema hasn't been registered for model "Zone".
Use mongoose.model(name, schema)
at new MissingSchemaError (/home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/error/missingSchema.js:22:11)
at NativeConnection.Connection.model (/home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/connection.js:888:11)
at getModelsMapForPopulate (/home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/model.js:4337:57)
at populate (/home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/model.js:3915:21)
at _populate (/home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/model.js:3885:5)
at utils.promiseOrCallback.cb (/home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/model.js:3858:5)
at Object.promiseOrCallback (/home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/utils.js:248:12)
at Function.Model.populate (/home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/model.js:3857:16)
at Patient.find.lean.populate.exec (/home/amine/ubudu/app_mn/sprint0/server/controllers/patientController.js:61:14)
at /home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/model.js:4733:16
at /home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/utils.js:263:16
at _hooks.execPost (/home/amine/ubudu/app_mn/sprint0/server/node_modules/mongoose/lib/query.js:4224:11)
at /home/amine/ubudu/app_mn/sprint0/server/node_modules/kareem/index.js:135:16
at process._tickCallback (internal/process/next_tick.js:61:11) message: 'Schema hasn\'t been registered for model "Zone".\nUse
mongoose.model(name, schema)', name: 'MissingSchemaError' }
As long as you are using one of the more recent versions of mongoose, you can populated deeply nested values in one query.
Patient.find()
.populate({
path: 'path',
populate: {
path: 'zones'
}
}).exec()

MongoDB: How to populate an embedded reference

I'm unsure of how would I populate the questions field in the examBoard collection in the following example (I have made my example reasonably complicated on purpose so I can properly understand how it works).
examBoard schema:
var topicSchema = new mongoose.Schema({
name: String,
questions:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"question"
}
],
});
var moduleSchema = new mongoose.Schema({
name: String,
topics: [topicSchema]
});
var examBoardSchema = new mongoose.Schema({
name: String,
modules: [moduleSchema]
});
module.exports = mongoose.model("examBoard", examBoardSchema);
question schema:
var partSchema = new mongoose.Schema({
mark: Number,
content: String
});
var questionSchema = new mongoose.Schema({
content: String,
mark:Number,
methods:[[partSchema]]
});
module.exports = mongoose.model("question", questionSchema);
How I thought I should do it:
examBoard.find()
.populate
({
path:"modules.topics.questions",
model:"question"
})
.exec(function(err,exam)
{
if(err)
{
console.log("Failed to populate");
}
else
{
console.log("exam[0].modules[0].topcis[0].questions\n"+exam.modules[0].topcis[0].questions);
}
});
Try this:
Exam
.find()
.exec()
.then((exams) => {
// Populate questions
Exam
.populate(exams, {
path: 'modules.topics.questions',
model: 'question'
})
.then((populatedExams) => {
// Do something with populated exams
});
});

Mongodb,express find data by _id with multiple condition

My code is shown below:
PostCategory.find({categoryid:category._id.str},function(err,postcategories){
if(err) return next(err);
Post.find({_id:postcategories.postid},function(err,posts){
if(err) return next(err);
return res.render(__dirname + "/views/categorydetail", {
title: 'İletişim',
stylesheet: 'contact'
});
});
});
I want to find all post which _id is in postcategories.postid. My postcategories returns me list. Here is my postcategories model:
module.exports = function(){
var PostCategorySchema = new mongoose.Schema({
postid:String,
categoryid:String,
createddate:{ type: Date, default: Date.now }
});
mongoose.model("PostCategory",PostCategorySchema);
};
Any idea?
First of all, your Mongoose model needs to be something like that:
var PostCategorySchema = new mongoose.Schema({
postid: { type: mongoose.Schema.Types.ObjectId, ref: 'Post' },
categoryid: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
createddate:{ type: Date, default: Date.now }
});
mongoose.model("PostCategory", PostCategorySchema);
The ref option is what tells Mongoose which model to use during population, in our case the Post model (same thing for categoryid field).
After that, your request becomes really simple:
var query = PostCategory.find({ categoryid: category._id });
query.populate('postid');
query.exec(function (err, postcategories) {
if (err) return next(err);
// res.render('......');
});
For more information, you should read the Mongoose Query Population documentation.
EDIT:
So, if you have more than one post for a postcategory, update the model to:
var PostCategorySchema = new mongoose.Schema({
postid: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }],
categoryid: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
createddate:{ type: Date, default: Date.now }
});
the simple way is :
PostCategory.find({categoryid:category._id.str},function(err,postcategories){
if(err) return next(err);
var ids = [];
_.each(postcategories, function(postCategory){
ids.push(postCategory.postid);
});
Post.find({_id : { $in : ids } },function(err,posts){
if(err) return next(err);
return res.render(__dirname + "/views/categorydetail", {
title: 'İletişim',
stylesheet: 'contact'
});
});
)};
In my example, i use underscoreJS to fetch postCategories List

Categories