infinite population mongoose node js - node.js

I have got two models which are ( form, user )
each user has formId field which is the object id of the form object he has
each form has a field called userId which is for the user who has this form
the problem is that I am using mongoose-autopopulate package and if I changed the formId and userId fields to be auto-populated it will open an infinite population with no end
the problem is that some other schemas have a field called formId which is associated with the form object and in this case I want to populate the userId field to get the user info without populating again the formId field.
Schemas Design
const userSchema = new Schema({
name: String,
age: Number,
formId: {
type: Schema.Types.ObjectId,
ref: 'Form',
//this value used to auto populate for mongoose-autopopulate package
autopopulate: true,
},
})
//signing the mongoose-autopopulate plugin
...
//exporting the module
---------------
const formSchema = new Schema({
address: String,
bill: Number,
//the id of the user who added this form
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
//this value used to auto populate for mongoose-autopopulate package
autopopulate: true,
},
})
//signing the mongoose-autopopulate plugin
...
//exporting the module
----------
const orderSchema = new Schema({
products: [],
deliveryBoy: {
type: Schema.Types.ObjectId,
ref: 'Boy',
},
formId: {
type: Schema.Types.ObjectId,
ref: 'Form',
//this value used to auto populate for mongoose-autopopulate package
autopopulate: true,
},
})
//signing the mongoose-autopopulate plugin
...
//exporting the module
Thanks,

Use the maxDepth option mongoose-autopopulate
for example
const orderSchema = new Schema({
products: [],
deliveryBoy: {
type: Schema.Types.ObjectId,
ref: 'Boy',
},
formId: {
type: Schema.Types.ObjectId,
ref: 'Form',
autopopulate: { maxDepth: 2 },
},
})

Related

How to define schema for personal collection with different type of items with Mongoose and Nodejs

I am creating personal collection web app in which users can create their own collection including different item such as books, whiskey, poststamps... etc. I created schema for this but now i realised i created only for items not for collections. So i need some help to define my collections schema in which users can create different items and some properties of item should be changeable because of item type.For example, I want to store a book collection. I can select (add to standard set of id+name+tags) additional string field “Author”, additional text field “Synopsis”, addition data field “Publication Year”. Maybe with Whiskey or another collection
Here is my DB structure:
User Schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
import bcrypt from "bcrypt";
const userSchema = new Schema(
{
username: { type: String },
email: { type: String, unique: true},
password: { type: String },
role: { type: String, enum:["user", "admin"], default:"user"},
status: {type: String, default:"active"},
collections: [{ type: Schema.Types.ObjectId, ref: 'Collection' }]
},
{ timestamps: true }
);
Collection schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const collectionSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
comments:[{
user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
text: String,
}],
user: [{ type: Schema.Types.ObjectId, ref: "User" }],
likes:[{ type: Schema.Types.ObjectId, ref: 'User' }],
},
{ timestamps: true }
);
collectionSchema.index({'$**': 'text'});
export default model("Collection", collectionSchema);

How to populate fields present inside a map type schema in mongoose?

I have my mongoose schema as follow
const instructorSchema = new mongoose.schema({
coursesByMe: [
{
course: {
type: ObjectId,
ref: "Course",
},
submissions: {
type: Map,
of: Submission.schema,
},
},
],
active: {
type: Boolean,
default: false,
},
});
My submission schema is a simple schema
const submissionSchema = new mongoose.Schema({
user: {
type: ObjectId,
ref: "User",
},
subFile: String,
});
module.exports = mongoose.model("Submission", submissionSchema);
I want to populate the user field but I am unable to as the type of submissions is of map type schema.
Any help with this would be really grateful. Thank you.

Embedding another mongoose schema

I'm trying to embed a model in a mongoose schema. Here's what I have:
const People = {
userId: {
type: mongoose.Schema.Types.objectId,
required: true,
ref: 'User'
},
locationId: {
type: mongoose.Schema.Types.objectId,
required: true,
ref: 'Location'
},
};
const Person = mongoose.model(
'Person',
new mongoose.Schema({
...People,
gender: {
type: String
}
})
);
const shmanian = await new Person({gender: 'other', userId:'someUserId', locationId: 'someLocationId'}).save();
The response I get is {gender: 'other'}
The problem is that people doesn't get populated when I create Person.
You should embed an array of "Person" inside a model "People". For example,
const Schema = require("mongoose").Schema;
const model = require("mongoose").model;
const Person = new Schema({
userId: {
type: mongoose.Schema.Types.objectId,
required: true,
ref: 'User'
},
locationId: {
type: mongoose.Schema.Types.objectId,
required: true,
ref: 'Location'
},
});
const People = new Schema({
person: [Person]
});
module.exports = model("People", People);
Here, everytime you create a new Person, you can add it to the People model which contains an array of Person objects.
Not a mongoose Problem.
People is undefined when you create the Object Person.
Thus it doesn't get populated.
Try switching both assignments.

How to name a foreign key different from db name in mongoose

Is there a way in mongoose + Node.js/Express to define the relation between the foreign key field and what I refer to that field in the model is? My issue is that I have a mongo database where my foreign keys are all formatted like 'exampleId' instead of 'example'. I could just call out 'exampleId' directly but then it leads to weird things like when I populate 'exampleId' instead of 'example' (which is confusing because once populated, it is now the 'example' itself instead of its id).
Here is how I do it now and it works with my graphQL server, but only if my field in the database is 'course' while my database's field is 'courseId'
const CourseSchema = new Schema({
_id: { type: String },
sections: [{
type: Schema.Types.String,
ref: 'Section'
}],
});
const SectionType = new GraphQLObjectType({
name: 'SectionType',
fields: () => ({
id: { type: GraphQLID },
courseId: {
type: require('./course_type'),
resolve(parentValue) {
return Section.findById(parentValue)
.populate('course')
.then(section => section.course);
}
},
}),
});
I figured it out! With the newest version of mongoose, you actually can use virtual fields to accomplish what I wanted to do and this technique allows for flexibility in laying out your schema. Say that my MongoDB collections look like the following:
Courses { _id, sectionIds }
Lectures { _id, courseId }
I can use the following schema in mongoose and it will allow me to refer to course.lectures or lecture.course instead of the usual course.lectureIds or section.courseId:
const CourseSchema = new Schema({
_id: { type: String },
});
CourseSchema.virtual('sections', {
type: Schema.Types.String,
ref: 'Section',
localField: 'sectionIds',
foreignField: '_id',
justOne: false,
});
CourseSchema.statics.findSections = function(id) {
return this.findById(id)
.populate('sections')
.then(course => course.sections);
}
const SectionSchema = new Schema({
_id: { type: String },
});
SectionSchema.virtual('course', {
type: Schema.Types.String,
ref: 'Course',
localField: 'courseId',
foreignField: '_id',
justOne: true,
});
Actually MongoDB isn't a relational database. You can alter the field and its name whatever you like. Ex I Have an Owner(Meteor.users) table and Patient Table with this column
ownerid : {type: String, min: 1},
firstname: {type: String, min: 1},
lastname: {type: String, min: 1},
middlename: {type: String, min: 1, optional: true},
createdbyid: { type: String },
createdbyname: { type: String },
createdat: { type: Date, defaultValue: new Date() },
updatedbyid: { type: String, optional: true },
updatedbyname : { type: String, optional: true },
updatedat: { type: Date, defaultValue: new Date() },
I can easily stamp the value of my {Meteor.Users()._id} to ownerid of my designated patient by just processing them at meteor.methods. You don't have to worry about foreign keys mongo doesn't do relational databases you can customize your database whatever you like. I Hope this helps ;)
Mongoose Documentation posits that _id has to be used in refs and that[i]t is important to match the type of _id to the type of ref. , e.g.:
var personSchema = Schema({
_id : Number, //it is `Number`
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }] // use `Number` to match
});
I also wonder if by 'database' you mean 'collection'.

Select specific field from documents in mongoose

Hi I have three Schemas with this field's
var interactionSchema = new Schema({
pollee: { type: ObjectId, ref: 'Pollee' },
answers: { type: [ObjectId], ref: 'Answer', autopopulate: true },
status: type: String
});
var PolleeSchema = new Schema({
firstName: String,
lastName: String,
gender: String,
user: { type: ObjectId, ref: 'User', required: true },
interactions: { type: [ObjectId], ref: 'Interaction', autopopulate: true }
});
var userSchema = new Schema({
email: String,
pollee: { type: Schema.Types.ObjectId, ref: 'Pollee', autopopulate: true }
});
I need to realize a query in Pollee and pupulate fields from user and interactions, but from interactions I only need the status field, I dont need answers and other ObjectID arrays that contain the Interactions colection.
I made this Query
Pollee.find(req.body.filters)
.select('id age birthday country device_register gender municipality state parish user interactions.status')
.populate('user','email createdAt')
.exec(function(err,pollees){
//Other
}
//....
This return interactions array but status field is not returned. If I write only interactions on the select, return interactions with all fields from interactions.
I try this
Pollee.find(req.body.filters)
.select('id age birthday country device_register gender municipality state parish user')
.populate('user','email createdAt')
.populate('interactions', 'status')
.exec(function(err,pollees){
//Other
}
//....
This return nothing from interactions
I need only Status field from interactions.
The problem here is the interactions field from Pollee Schema, this field its a Array of ObjectsId, and this field its autopopulated from Schema. I want to select only the status field from interactions
Any idea?
I see that you are using mongoose-autopopulate.
It is stated in their document that you can do like this:
var PolleeSchema = new Schema({
//...
interactions: { type: [ObjectId], ref: 'Interaction', autopopulate: { select: 'status' } }
});

Resources