Mongoose populating array inside nested schema - node.js

This is my schema:
var userSchema = {
folders : [ folderSchema ],
...
}
var folderSchema = new mongoose.Schema({
itemlist : [{ type: String, ref: 'Item', required: true }],
foldername : { type: String},
...
});
// Item model
var itemSchema = {
name: { type: String },
...
}
I would like to populate itemlist (entire array) inside of each folderSchema, is this possible?
What I've tried so far but doesn't work:
userModel.findOne({ _id: userId }, null, callback).populate({
path: 'folders.$.itemlist',
select: 'name'
});
This post and this post are similar but they store the folder models and have a ref instead of nested document.
Bonus: is it possible to select only some folders by foldername to populate their itemlist?

I think you are looking for "deep population", see the population section "Populating across multiple levels"
rewrite your populate to:
userModel.findOne({ _id: userId }, null, callback).populate({
path: 'folders',
populate: { path : 'itemlist'}
});

The easiest solution is to actually retrieve the nested folder and perform a find manually. Then simply call find({_id: {$in : folder}}); to find all elements of array.

Related

Mongoose/MongoDB : How to update item which is nested 4 levels down?

In my mongo database I have a tree like this:
-shopping-lists
|- list
|-products
|-item
|-item
|- list
|-products
|-item
|-item
I need to find which shopping list I'm updating and then go to products array, find an item inside and update one property.
I'm trying to solve this from few hours right now, but didn't find any solution.
How to update item which is nested 4 levels down??
After 6 hours of investigation, I have found an answer.
For any of you guys, having the same problem here is the answer.
While adding a new item to the Parent model, I've been just pushing these items as plain objects and the Parent model was like this:
const Parent = new Schema(
{
description: { type: String },
childrenArray: [Object],
},
{ timestamps: { createdAt: 'created_at' }, collection: 'shopping-lists' }
);
The problem was in childrenArray, that in the model I had declared this an array of objects.
Changing this to ChildrenModel solved the problem, cause now these items are saved as mongoose subdocuments and I can operate on then using $ operator.
new Schema looks like this:
const Children = new Schema(
{
prop1: { type: String, required: true },
prop2: { type: String, required: true },
prop3: { type: String },
},
{ timestamps: { createdAt: 'createdAt' } }
);
const Parent = new Schema(
{
description: { type: String },
products: [ItemSchema],
},
{ timestamps: { createdAt: 'created_at' }, collection: 'shopping-lists' }
);
Now I can easily access subdocuments like this:
const { name, isOrdered, author, voterIds, _id, listId } = req.body;
Parent.findOneAndUpdate(
{ _id: listId, 'children._id': _id },
{
$set: {
'children.$.isOrdered': true
}
},
(err, doc) => {
console.log(doc);
}
);
As far as i know We can update the nested document by positional operator that is $ but as according to the mongodb documentation we cannot update property nested more then 2 levels deep array. In simple you cannot use $ positional operator two times like "shoppinglists.$.list.$.products so its better to change the structure of your db to do it in better way

Nest mongoose schema within itself?

Is it possible with mongoose to create a schema, call it Folders and it has a property within called subfolders that is an array of nested Folder subdocs?
const mongoose = require('mongoose')
let SubSchema = mongoose.Schema({
name: { type: String, required: true }
})
let FolderSchema = mongoose.Schema({
name: { type: String, required: true },
children: [ SubSchema ]
})
I know I can nest subdocs in an array by referencing another schema similar to what is shown above. What I'm looking to do though is reuse FolderSchema within itself. Obviously this causes an issue because at the time of creation of the schema, FolderSchema doesn't exist. Is there a better way to do this? Is there a way to recursively nest documents using the same schema?
I know I could have the array be a list of ObjectId that reference a collection but I was hoping to just keep it all nested as documents. I guess if I did populate() to let it resolve the doc ids, that would essentially be the same thing. Just wondering if there is another method I wasn't aware of.
I haven't tried this personally, but I have read this can be achieved by simply referencing this in the field you want to reference the current model.
The model you would like to will look something like this,
const mongoose = require('mongoose')
const FolderSchema = mongoose.Schema({
name: { type: String, required: true },
type: { type: String, enum: ['file', 'directory'],
children: [ this ]
})
const FolderModel = mongoose.model('Folder', FolderSchema);
Hope that helps!
look you need to clarify your question a little bit but as much as i understood from the question, yes it can be done in this way :
var mongoose = require('mongoose');
var FolderSchema = new mongoose.Schema({
SubFolders = [ type:monogoose.Schema.Types.ObjectId, ref : 'Folders']
});
var folder = mongoose.model('Folders',FolderSchema);
module.exports = folder;
This shall work for you.
So for infinite object having children, I did it like so:
mongoose schema:
const itemSchema = new mongoose.Schema({
name: String,
items: {
type: [this],
default: undefined
}
}, { _id: false })
const mainSchema = new mongoose.Schema({
name: String,
items: {
type: [itemSchema],
default: undefined
}
})
output example:
[
{
_id: '62a72d6915ad7f79d738e465',
name: 'item1',
items: [
{
name: 'item1-item1',
items: [
{
name: 'item1-item1-item1'
},
{
name: 'item1-item1-item2'
},
{
name: 'item1-item1-item3'
},
]
},
{
name: 'item1-item2'
}
]
},
{
_id: '62a72d6915ad7f79d738e467',
name: 'item2'
},
{
_id: '62a72d6915ad7f79d738e467',
name: 'item3',
items: [
{
name: 'item3-item1'
}
]
}
]

How to popoulate recursive schema references Mongodb, Mongoose, Express?

Using mongoose and Express with mongodb
So right now I have a schema for boxes, a box can contain objects or it can contain other boxes:
my schema for boxes looks like this:
var box = new Schema({
boxId: ObjectId,
boxContents: [{
contentType: {
type: String,
enum: ["box", "object"]
},
typeId: {
subBox: {
type: Schema.Types.ObjectId,
ref: 'box'
},
subObject: {
type: Schema.Types.ObjectId,
ref: 'object'
}
}
}]
});
I made sure to have my 'ref' labeled accordingly with the model names so I don't believe that is the problem. I create a new document like so:
var box1 = new Box({
contents: [{
contentType: 'object',
typeId: {
subObject: object1._id
}
}]
});
When I use:
Control.find({}).populate('contents.typeId')
.exec(function(error, posts) {
console.log(JSON.stringify(posts, null, "\t"));
});
It doesn't populate the subBox and subObject fields :( If I try to access the subBox or subObject fields, it gives me undefined.
What am I doing incorrectly?
First of all, you need to get a model of the collection:
var BoxModel = mongoose.connect(dbURI).model("box", box);
boxContents is in schema, but in the object is contents, that should be modified.
To create an object to be save, you need to use the model in that way, and then you can get your populated data this way:
var box1 = new BoxModel({
boxContents: [{
contentType: 'object',
typeId: {
subObject: object1._id
}
}]
});
BoxModel.find({}).populate('boxContents.typeId');
OR
BoxModel.find({}).populate({path:'boxContents.typeId'});

Compare Array with Collection-Array containing Objects

This is my collection schema:
var objectSchema = new Schema({
members: [{
user_id: ObjectId,
settings: {
type: Boolean
}
}],
title: String
});
And now I'm trying to search for objects with specific members (identified by their "user_id", for example ["asdf123lkd", "asdf1223"]).
Is there any way to search for these objects?
Thanks!
You can try this:
objectModel.find({ 'members.user_id' : {'$in' : ['asdf123lkd', 'asdf1223']} }, function(err, data) {
console.log(err,data);
})

Mongoose: how to structure a schema with a SET of subdocuments (one unique field)?

I'm trying to make the following schema to work:
var FormSchema = new mongoose.Schema({
form_code: { type: String, unique: true },
...
});
var UserSchema = new mongoose.Schema({
...
submissions: [{
form_code: { type: String, unique: true },
last_update: Date,
questions: [{
question_code: String,
answers: [Number]
}]
}],
});
The rationale here is that a user can have many unique forms submitted, but only the last submission of each unique form should be saved. So, ideally, by pushing a submission subdocument when updating a user, the schema would either add the submission object to the set, or update the subdocument containing that form_code.
The following code doesn't work as desired (it pushes the new subdocument even if the form_code is already present):
User.findOneAndUpdate(
{ _id: user.id },
{ $addToSet: { submissions: submission_object } },
function (err, user) {
// will eventually have duplicates of form_code at user.submissions
}
);
The above schema clearly doesn't work, what must be changed to achieve that "upsertToSet"?

Resources