Nest mongoose schema within itself? - node.js

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'
}
]
}
]

Related

How to make a nested Schema in Nodejs

name:"salman,
protein:23,
carbs:23,
calorie:1221,
fats:12,
ingredients:{
salt:1 teaspoon,
......
}
I want a schema like this how can I make a schema of this with nodejs mongoose
also how can i add data in this nested schema because am getting error
Initially you have to create the table schema like this:
const mongoose = require('mongoose');
// Health Schema
const HealthSchema = new mongoose.Schema({
name: {
type: String,
},
protein: {
type: String,
},
carbs: {
type: String,
},
calorie: {
type: String,
},
fats: {
type: String,
},
ingredients: {
type: object,
default: {
salt: '',
fibre: ''
}
},
});
module.exports = mongoose.model(
'health',
HealthSchema
);
Here ingredients objects have priorly set the keyname. So you have to just pass the value at the time of creation.
I'm gonna skip alot of things here.
In your schema do something like,
ingredients:[String]
when creating new data do something like
const healtData= await new healtData({... the data here})
the do something like this before calling save
healthData.ingredients.push(ingredient)
healthData.save()

Find Object and Update by pushing to nested Array in MongoDb

I have created a Mongoose Model which holds nested arrays exercises>history>data. I want to make a put request and push an Object, consisting of the time the data was createdAt as well as an array of the Users data to the history of the exercise that was run. However, the following attempt did not work:
User.findOneAndUpdate(
{ _id: req.user.id, "exercises.title": req.body.exercise_title },
{ $push: { "exercises.$.history": { data: [1,2,3,4,5] } } }
);
My Schema looks as follows:
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
userName:{
type: String,
required: true},
exercises:[{
title:{
type: String,
},
history: [{
createdAt: {
type: Date,
default: Date.now
},
data: []
}]
}]
});
module.exports = mongoose.model('User', UserSchema)
I have no clue why my query is not working

How to sort in mongoose by specific order?

I have Mongoose model:
const mongoose = require('mongoose')
const { Schema } = mongoose
const schema = new Schema({
Name: { type: String },
Category: { type: String },
Price: { type: Number }
})
module.exports = mongoose.model('Product', schema)
And I have to sort by Category field. Sort order is
['Clothes', 'Accessories', 'Footwears']
How cat I do it?
The MongoDB server doesn't offer any way to provide a custom sort function.
Javascript does, so you can get the results from the query as an array, and use a custom compare function with Array.sort
I solved it by adding weight of Category. Now my model is like this:
const schema = new Schema({
Name: { type: String },
Category: { type: String },
CategoryWeight: { type: Number },
Price: { type: Number }
})
And I sorting like this:
const products = await Product.find().sort('-CategoryWeight')

Mongoose - Save array of strings

I can't save an array of strings into my DB using Mongoose.
(Note all code below is simplified for ease of writing here)
So i declare a variable of a person schema I have:
var newPerson = new Person ({
tags: req.body.tags
});
The schema itself looks like:
var personSchema = new mongoose.Schema({
tags: Array
});
And when it comes to saving its just a simple:
newPerson.save(function(err) {
//basic return of json
});
So using Postman I send in an array in the body - however everytime I check the DB, it just shows one entry with the array as a whole i.e. how I sent it:
Any ideas what extra I'm supposed to do?
Write up from my comment:
The way to specify an array of strings in mongoose is like so:
var personSchema = new mongoose.Schema({
tags: [{
type: String
}]
However, the problem here is most-likely to do with Postman as it is sending the 'array' as a string. You can check this by checking the type of req.body.tags like so:
console.log(typeof req.body.tags)
If this returns a String, make sure to set the content-type in Postman to JSON as seen in this screenshot rather than the default 'form-data' option.
var schema = new Schema({
name: String,
binary: Buffer,
living: Boolean,
updated: { type: Date, default: Date.now },
age: { type: Number, min: 18, max: 65 },
mixed: Schema.Types.Mixed,
_someId: Schema.Types.ObjectId,
decimal: Schema.Types.Decimal128,
array: [],
ofString: [String],
ofNumber: [Number],
ofDates: [Date],
ofBuffer: [Buffer],
ofBoolean: [Boolean],
ofMixed: [Schema.Types.Mixed],
ofObjectId: [Schema.Types.ObjectId],
ofArrays: [[]],
ofArrayOfNumbers: [[Number]],
nested: {
stuff: { type: String, lowercase: true, trim: true }
},
map: Map,
mapOfString: {
type: Map,
of: String
}
})
// example use
var Thing = mongoose.model('Thing', schema);
var m = new Thing;
m.name = 'Statue of Liberty';
m.age = 125;
m.updated = new Date;
m.binary = Buffer.alloc(0);
m.living = false;
m.mixed = { any: { thing: 'i want' } };
m.markModified('mixed');
m._someId = new mongoose.Types.ObjectId;
m.array.push(1);
m.ofString.push("strings!");
m.ofNumber.unshift(1,2,3,4);
m.ofDates.addToSet(new Date);
m.ofBuffer.pop();
m.ofMixed = [1, [], 'three', { four: 5 }];
m.nested.stuff = 'good';
m.map = new Map([['key', 'value']]);
m.save(callback);
On Schema:
( Since you have mentioned in the problem that it is an array of strings )
var personSchema = new mongoose.Schema({
tags:{
type:[String],
required: true
}
});
On Postman:
{
"tags": ["css", "javascript", "mongoose", "node"]
}
On MongoDB
{
"tags":["css", "javascript", "mongoose", "node"]
}
Similarly, you can create other types of primitive arrays and document arrays in the mongoose schema as:
({
toys: [ToySchema],
buffers: [Buffer],
strings: [String],
numbers: [Number]
// ... etc
});
Try changing the schema to
var personSchema = new mongoose.Schema({
tags: [{type: String}]
});
or you can use Mixed type
var personSchema = new mongoose.Schema({
tags: mongoose.Schema.Types.Mixed
});
EDIT
i think the problem is with assignment. Use:
person.tags.push("string to push");
On Schema
techs: Array
On Postman
"techs": ["express","rect","html","css","scss"]
On DB (MongoDB)
"techs" : [
"epxress",
"rect",
"html",
"css",
"scss"
]
var personSchema = new mongoose.Schema({
tags: [{type: String}]
});
Use this in the schema.
Saving the Array:
var etc = new modename({yourprimaryid: primaryid});
for (var i = 0; i < tag.length; i++) {
etc.tag.push(tag[i]);
}
etc.save(function(err) {
//whatever you want here
}
Define a Schema:
const schema = new Schema({
name: { type: String, required: true },
tags: [String]
});
In postman add each element separately using the array syntax below
name:Thing
tags[]:task
tags[]:other
tags[]:thing
Return Data:
{
"__v": 0,
"name": "Thing",
"_id": "5a96e8d0c7b7d1323c677b33",
"tags": [
"task",
"other",
"thing"
]
}
this will also work
var personSchema = new mongoose.Schema({
tags: {
type: [String], default: []
}
});
Firstly, as many people have noted, the schema needs to change to indicate that the tags field is intended to hold an array of strings, and not just a single one. So that needs to change to:
var personSchema = new mongoose.Schema({
tags: [String]
});
The other thing you need to keep in mind (and which caused me a lot of trouble), is that when saving, make sure to use a fresh array for the tags field. For example, this won't work:
person.tags[0] = "new tag";
person.save();
Instead, you need to do something like:
person.tags = person.tags.slice(); // Clone the tags array
person.tags[0] = "new tag";
person.save();
Hope this helps.
I had a simialr problem,
In the model, do this :
tags : {[String], default: undefined}
So that it defaults to undefined unstead of an empty array,
and instead of this:
const person = new Person({
tags : req.body.tags
});
Do this :
const person = new Person();
person.tags = req.body.tags;
My requirement;
ingredients: Type Array of Strings
Solution:
ingredients: {
type: [String],
},
const productSchema = new mongoose.Schema(
{
name: {
type: String,
},
description: {
type: String,
},
price: {
type: String,
},
categoryId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
},
sellerId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Seller",
},
discount: {
type: String,
},
status: {
type: String,
default: "active",
enum: ["active", "inactive", "deleted"],
},
images: {
type: Array,
required: true,
},
},
{ timestamps: true }
);

Structure for deep nests in mongoose

Mongo noob here. I'm building a mongoose schema with a lot of one-to-many relationships, and this seems to be a good opportunity to use nesting. I have a collection "countries", each has many "states", each has many "cities", each has many "people." I'm going to want to run all different sorts of queries...get states by country, insert new city into state, remove a person from a city, etc.
How do I structure it? My current schema looks like this:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
;
var countrySchema = Schema({
name: { type: String },
states: [ {
name: { type: String },
cities: [ {
name: { type: String },
people: [ {
name: { type: String }
} ]
} ]
} ]
});
To me, that makes sense. I will likely be pulling entities based on deep nests, so this kind of nested schema should give me the performance edge that a heavily-joined relational database won't (right?).
It is, however, very ugly. I have also seen this style of schema construction:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
, ObjectId = Schema.ObjectId
;
var countrySchema = mongoose.schema({
name: { type: String },
states: [ { type: ObjectId, ref: State } ]
});
var stateSchema = mongoose.schema({
name: { type: String },
cities: [ { type: ObjectId, ref: City } ]
});
var citySchema = mongoose.schema({
name: { type: String },
persons: [ { type: ObjectId, ref: Person } ]
});
var personSchema = mongoose.schema({
name: { type: String },
});
var Country = mongoose.model('Country', countrySchema)
, State = mongoose.model('State', stateSchema)
, City = mongoose.model('City', citySchema)
, Person = mongoose.model('Person', personSchema)
;
Is this a better way to do it? It seems more readable, but I imagine it doesn't perform as well.

Resources