Mongoose Populate and Search by Array of References - node.js

I'm trying to wrap my head around the Mongoose Populate syntax and structure. I have two schemas. The Parent has an array of Child references.
const Parent = new Schema({
name: String,
children: [{type: Schema.ObjectId, ref: 'Child'}]
});
const Child = new Schema({
name: String
});
To populate the Parent I've been doing this:
Parent
.findById(parent.id)
.populate('children')
.exec( (err, parent) => {
parent.children = arrayOfInsertedChildDocs;
parent.save();
});
The Parent references save, but is there a way to query for Parents that have a reference to a certain Child? For example all Parents that have a reference to a child with the Id of ObjectId('xxxxxxxxx') in their children array?
This is what I've been trying but it's not working.
let query = { "children._id": mongoose.Types.ObjectId(childId) };
Parent.find(query, (err, parents) => {
//process parents
})
Is this possible?

Figured it out. The query to get the Parent from a child id in the nested array is:
Parent
.find({"children":ObjectId(child.id)})
.populate("children")
.exec((err,parents) => {
//process parents
});

You want to search for element in MongoDB array set. Suppose you have a document.
{
name :"harry",
childen:["10ahhdj20","9ajskjakj9","8aiisu38","2jjaksjah0"]
}
So for searching inside an array list, you can use this.
db.parents.find( { tags: { $all: [ "10ahhdj20", "812922dd" ] } } )
You will get all the parents who have these children.

Related

Node Js and Moongoose: How to loop into array of objects and delete a particular object and then update the whole document

My document schema is as follows:
const CollectionSchema = mongoose.Schema({
ImageCategory:{type:String,required:true},
imgDetails: [
{
_id: false,
imageUrl:{type:String},
imageName:{type:String},
imageMimeType:{type:String},
}
],
Date: {
type: String,
default: `${year}-${month}-${day}`,
},
},{timestamps: true,})
So in the database for example one document has multiple images with a single image category. What I am trying to do is I want to delete an object from imgDetails array.
Let me explain my question more precisely: imgDetails is an array
Explanation: I want to loop in imgDetails and then find (where imgageUrl === req.body.imageUrl) if its match delete that whole object which have that req.body.imageUrl and then update the document.
Please guide me on how to write such a query. Regards
Demo - https://mongoplayground.net/p/qpl7lXbKAZE
Use $pull
The $pull operator removes from an existing array all instances of a value or values that match a specified condition.
db.collection.update(
{},
{ $pull: { "imgDetails": { imageUrl: "xyz" } } }
)

i want to make my route wait to all the process to be done with nodeJS

i have a little complicated route which i want to modify what i get back from the database with mongoose
when it ends me the array of object of the items, each object contains an array of ID of another collection witch i have to add ass a new property to each object,
the code looks like this:
/* here i am trying to get the list of items */
let itemsList = await Items.find().lean();
/* now i want to loop through them to go to each ones inner array of IDs */
itemsList.forEach(item => {
/* here i am making a new object property to containg what the IDs pointing at */
item.theProducts = [];
/* now i am going through the array of IDs */
item.IDsArray.forEach(async product => {
/* finding each product by the ID */
let foundProduct = await SlemaniMaxzan.findById(product, { _id: 0, productName: 1, productPrice: 1 }).lean();
/* showing the product */
console.log(foundProduct);
/* now i am pushing it to the new property */
item.theProducts.push(foundProduct);
});
});
/* trying to check it the values has been added */
/* i expect the values has been added jsut fine, but it is not working */
console.log(itemsList);
res.render("mandubakan", { title: "list", mandubakan: itemsList });
when i run it, it has not been added and it just made a new empty array to the items but not added anything to it, and the program logs the itemsList even before loging each foundProduct
You must avoid method forEach for asynchronous functions.
Try something like that:
let itemsList = await Items.find().lean();
for (let item of itemsList) {
item.theProducts = [];
for (let product of item.IDsArray) {
let foundProduct = await SlemaniMaxzan.findById(product, {
_id: 0,
productName: 1,
productPrice: 1,
}).lean();
console.log(foundProduct);
item.theProducts.push(foundProduct);
}
}
console.log(itemsList);
res.render("mandubakan", { title: "list", mandubakan: itemsList });

Push Array Items to Array type Column in mongoDb

This is a Controller in which I'm trying to catch multiple candidates id(ObjectId) and try to store it in the database in the array Candidates. But data is not getting pushed in Candidates column of Array type.
routes.post('/Job/:id',checkAuthenticated,function(req,res){
var candidates=req.body.candidate;
console.log(candidates);
Job.update({_id:req.params.id},{$push:{Appliedby : req.user.username}},{$push:{Candidates:{$each:
candidates}}}
});
Console screens output
[ '5eb257119f2b2f0b4883558b', '5eb2ae1cff3ae7106019ad7e' ] //candidates
you have to do all the update operations ($set, $push, $pull, ...) in one object, and this object should be the second argument passed to the update method after the filter object
{$push:{Appliedby : req.user.username}},{$push:{Candidates:{$each: candidates}}
this will update the Appliedby array only, as the third object in update is reserved for the options (like upsert, new, ....)
you have to do something like that
{ $push: { Appliedby: req.user.username, Candidates: { $each: candidates } } }
then the whole query should be something like that
routes.post('/Job/:id', checkAuthenticated, function (req, res) {
var candidates = req.body.candidate;
console.log(candidates);
Job.update(
{ _id: req.params.id }, // filter part
{ $push: { Appliedby: req.user.username, Candidates: { $each: candidates } } } // update part in one object
)
});
this could do the trick I guess, hope it helps

Sub-document saving is not updating parent

I'm trying to learn some relationship mechanics in mongoose. I have two models, a parent and a child:
var childrenSchema = new Schema({
name : String,
date : {type : Date, default: Date.now},
attribute1 : String,
attribute2 : String,
})
var parentSchema = new Schema({
name: String,
children: [childrenSchema]
})
exports.parent = mongoose.model('Parent', parentSchema);
exports.children = mongoose.model('Person', childrenSchema);
I will create a parent object in an initial call, and send an asynchronous call to an api which fetches children information based on the child's name. While that async call is out, I return the parent as is, because the user doesn't need to see the children's information immediately.
var Parent = require('schema.js').parent;
var Child= require('schema.js').children;
function addParent(p){
var parent = new Parent();
parent.name = p.result.name;
var child = new Child();
child.name = p.result.childname;
parent.children.push(child);
getChildDetails(child); // Async function to get children info..
parent.save(); //Save the parent so the information we return is persisted.
return parent; //Children probably not fully populated here. Not a problem.
}
function getChildDetails(child){
var promiseapi = require('mypromiseapi');
promiseapi.fetch('childinfo',child.name).then(function(result){
child.attribute1 = result.attribute1;
child.attribute2 = result.attribute2;
}).then( function(){
child.save(); // I expect the parent's information to be updated.
});
}
However, I am now in a little bit of a desync issue. Parent object has the single child on it, but only name and some mongoose specific information is populated (objectId). A child table is created also, with the child information fully populated, and it has the same objectID as the child that's affixed to the parent.
Why does the object that is affixed to the parent not get updated when I save it independently elsewhere in my code?
I solved it by using Populations (http://mongoosejs.com/docs/populate.html) instead of the pure schemas. The new schema models look like this:
var childrenSchema = new Schema({
name : String,
date : {type : Date, default: Date.now},
attribute1 : String,
attribute2 : String,
})
var parentSchema = new Schema({
name: String,
children: [{type: Schema.Types.ObjectId, ref:'Child'}]
})
And the new addParent method looks like this:
function addParent(p){
var parent = new Parent();
parent.name = p.result.name;
var child = new Child();
child.name = p.result.childname;
parent.children.push(child._id);
child.save();
getChildDetails(child); // Async function to get children info..
parent.save(function(err,result){
Parent.populate(result,{path:'children'},function(err,resultparent){
return(result);
});
}); //Save the parent so the information we return is persisted.
}

Mixed schemas in a single subdocument array

If I have a parent schema like:
{
doc_name:String,
doc_collection:[?????]
}
and subdoc children:
child1 =
{
child_type: String,
property1: String,
property2: Number
}
child2 =
{
child_type: string,
different_property1: Number,
much_different_property2: String
}
can parentschema.doc_collection hold subdocuments of both child1 and child2 schemas?
Or do I have to do:
{
doc_name:String,
doc_collection:
{
child1:[child1],
child2:[child2]
}
}
I would normally create a subdocument schema that can encompass properties of ALL the types of objects I'm tring to stick in the array, but these are just too different. From the controller perspective, the child schemas are all of type doc_collection.
if my memories are good, mongoose doesn't handle complex type array (in term of content validation)
that means, if your model is like :
{
doc_collection : []
}
{
doc_collection : [child1]
}
is the same.
and the worst is that if your model is
{
doc_collection : [child1]
}
you would be able to add anythind in doc_collection array
myModel.doc_collection.push(anyChild2);
take a look to the array chapter : http://mongoosejs.com/docs/schematypes.html

Resources