How to populate through array in mongoose - node.js

I have a record like this,
"student" : [
ObjectId("5850e76196d4de3c1f4a0618"),
ObjectId("5850da3e7f3ff224767c196c")
],
I tried,
Classroom.findById(id).populate('student')
Can anyone suggest me that, how can I populate through this array.

Related

Mongo DB: Append a value to a nested array

I think there might be better ways to store data but the app I am working on has some data stored like this.
I have a document with nested arrays. In this particular example, would it be possible to append a new element "value3" to an array inside products whose "productId" matches the condition. So, basically look for productId and append "value3" to the array which has matching "productId".
I am just learning about MongoDB so if you can provide some suggestions for changing schema, even that would be very helpful.
P.S. Not sure if it helps but I am using node.js
{"_id":
{"$oid":"601baf0e5c307422c0fa958c"},
"sale":"Test Sale",
"products":[
[
["productId","value1","value2"],
["productId","value1","value2"]
],
[
["productId","value1","value2"],
["productId","value1","value2"]
],
[
["productId","value1","value2"],
["productId","value1","value2"]
]
],
"collectionProducts":["id","id","id"]
}
Maybe something like this:
db.store.update({},{$push:{"products.$[].$[k]":"value3"}},{ arrayFilters: [{ k:'productId' }]})

Insert a whole json Without creating different node in mongodb

i have a collection named drop down and i want to insert all the drop down static JSON values in a single collections without creating different node
for eg this is my json
"education": [
"Master",
"Bachelor"
],
"diet": [
"Veg",
"Non Veg"
]
Later on if i need to add more drop down values i don't have to alter the mongoose schema ,i could directly insert the json list
Is it possible or not? Sorry i am new to the Mongodb
Finally an idea strike on my mind and got the appropriate answer of my own question and like to share here. What i did is , I create the Schema as
const mongoose = require('mongoose');
const dropDownSchema = new mongoose.Schema({dropDown : mongoose.Schema.Types.Mixed})
module.exports.DropDownList =mongoose.model("DropDownList",dropDownSchema);
later on while passing data from the client
{
"dropDown":
{
"education": [
"Master"
,"Bachelor"
],
"diet": [
"Veg"
,"Non Veg"
]
}
}
While inserting data i first delete all data and insert the fresh one from the API
First find the document in that collection. Assume that we are requesting with the document _id and we are using mongoose model named Dropdown.
Example:
const document = await Dropdown.findOne({_id});
//Once you have found the document
// Add or change the existing fields
document[new_value_name] = new_values.map(val => val);
await document.save();
If you want to store it in array of object in mongodb then you can also create a schema with Array of dropdowns
var DropdownSchema = new mongoose.Schema({
dropdowns:[{
dropdown_key: { type: String },
dropdown_values: [{type: String}]
}]});
While inserting data you will need to loop through Object.keys of your json list and insert into as array . You can add number of dropdown as it is stored as array of object.
Please let me know if it helps.

$push on the basis $cond in mongodb?

I have Review schema having likeBy array contains the id of the users who likes the review...
I have to query it like
case 1: If id exist the pull it.
case 2: If id does not exist then push it.
Is it possible to do in a single query???
Review Schema
{
"_id" : ObjectId("5aa0f4aeb5cbb2313276cccc"),
"__v" : 0,
"likeBy" : [ ]
}
This is how I would have done it
db.people.findAndModify({
query: { likedBy : {idOftheUserinLikedArray: "anyId" }},
$push: { likedBy : {idOftheUserinLikedArray: "anyId" } },
new : true
})
I am not sure if that's what you want. Let me know if that works for you.
What this will do is, if it finds that Review object against the property your are searching for in likedBy array property of the documents it will return you the updated object so you can check the likedBy array if the value is inserted or not.
May be helpful
And don't forget to give it a look

mongoose exclude field in array

I have something like:
Schema Subdocument
name: String
data: Mixed
Schema Stuff
documents: [Subdocument]
Now, in my API there are two endpoints, one for the Subdocument and another for Stuff. When I want to get a Subdocument I need to contain the data field, but when I want to get Stuff, I want to show the name of those subdocuments, but I don't want to show the data field because is quite large and it won't be used.
So, to keep things clear, data is not private. It's just that I don't want it to be shown when I get it from Stuff
I tried by doing:
Stuff.findById(id)
.populate("documents")
.populate("-documents.data")
but that doesn't work... I'm getting the Stuffwith the Subdocumentcontaining the name and data. I feel like i'm missing to tell mongoose when I call populate("-documents.data") that documents is an array and I want to exclude the data field for each element in this array.
edit: Sorry the Schema I provided was not for my case. In my case it was not embedded, but a reference, like so:
Schema Subdocument
name: String
data: Mixed
Schema Stuff
documents: [{
type: Schema.Types.ObjectId,
ref: 'Subdocument'
}]
Assuming subDocument is not embedded and using as "ref" as you say populate is working but data part is not included:
Stuff.findById(id).populate( { "path" : "documents", "select" : "-data" })
Your documents have an "embedded" schema, so populate is not used here, it is used only for "referenced" schemas where the other objects are in another collection.
Fortunately with "embedded" there is an easy way using projection:
Stuff.findById(id,{ "documents.name": 1 },function(err,results) {
})
With results like
{ "documents": [{ "name": "this" },{ "name": "that" }] }
Or with .aggregate() and the $map operator:
Stuff.aggregate(
[
{ "$match": { "_id": ObjectID(id) } },
{ "$project": {
"documents": {
"$map": {
"$input": "$documents",
"as": "el",
"in": "$$el.name"
}
}
}}
],function(err,results) {
}
)
That will just tranform into an array of "only" the name "values", which is different to the last form.
{ "documents": ["this", "that"] }
Note, if using .aggregate() you need to properly cast the ObjectId as the autocasting from mongoose schema types does not work in aggregation pipeline stages.

MongoDB not updating subdocument within double-nested array (using Mongoose FindByIdAndUpdate) - EXACT POSITION KNOWN

I have a document structure that's roughly similar to the following:
{
"_id": "theIdOfThisObject",
"subdoc": {
"array": [
[
{
"parameters": {},
"winner": null,
"participants": [
"Person1",
"Person2"
]
},
{
"parameters": {},
"winner": null,
"participants": [
"Person3",
"Person4"
]
}
],
[]
]
},
}
I am entirely trying to replace one of the subdocuments within the nested array. I do not need to search for it - i know the exact position.
For example, I am trying to replace the first subdocument with
"parameters": {"frog":20},
"winner": "Person1",
"participants": [
"Person1",
"Person2"
]
which we'll say is saved as an object called newObject.
I expect the following code to work (and Model is a real Mongoose Model):
Model.findByIdAndUpdate('theIdOfThisObject',{$set: {'subdoc.array.0.0':newObject}}, function(err,doc){
console.log('doc is returned, but nothing is updated')
});
I have no idea what is going on and why this isn't working. Does anybody have any suggestions? I have been using MongoDB's native node driver for a very long time (3 years), but Mongoose is fairly new to me.
EDIT - adding schema as per comment request
The schema is pretty straightforward. looks as follows:
var Schema = new mongoose.Schema({
subdoc: {
array: [{}]
}
});
There's other fields in there, but this is the only one that matters in this case. My understanding is that having the Schema have a [{}] means that there will be an array of any kind of JSON arrangement. The Schema also lets me initially set the subdocument in question - it just doesn't let me update it for whatever reason.
I have figured out the issue. Apparently when using the Mixed Schema type, (which is the same as {}) with Mongoose, updating a subfield within the object is a 2 step process. You can't just use findByIdAndUpdate().
You must first use fineById(), grab the document in the callback, run markModified() on the document in question (passing in the path to the subdocument), and then finally save said document. Here's the code:
Model.findById('theIdOfThisObject', function(err,doc){
//update the proper subdocument
doc.subdoc.array[0][0] = newObject;
//then mark it as modified and save it
doc.markModified('brackets.rounds');
//save the model
doc.save(callback);
});
Maybe there are two things here.
First, in your sheme i recommend that you use
var Schema = new mongoose.Schema({
subdoc: {
array: [{type: Schema.Types.Mixed}]
}});
so that it is rightly defined as there can be anything.
Or the second thing that might could be missing. If the existing entry doesn't exist you have to set the option upsert :true that new entrys will also get inserted.
Model.findByIdAndUpdate('theIdOfThisObject',{$set: {'subdoc.array.0.0':newObject}}, {upsert : true},console.log);
I had the same problem and I can confirm, this line was the fix:
doc.markModified('brackets.rounds');

Resources