how can I ref a model that is in another folder? - node.js

for example the nexts schemas are in diferent folders like these:
cr/user
lms/content
this is the schemaContent
user: {
type: Schema.Types.ObjectId,
ref: 'cr/user'
}
How can I ref user from Content?
because when I used cr/user I get an error "Schema hasn't been registered for model"
I need just populate user from content like Content.find().populate({ path: 'users' }) Keeping user in the folder called cr and content in the folder called lms

You are trying to nest documents. Try below approach to nest document.
i will assume the directories cr and lms are inside the directory called demoproject
demoproject/cr/user.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name:{
type : String,
required: true
}
});
const User = mongoose.model("User",UserSchema);
module.exports = User;
demoproject/lms/content.js
./../cr/user - go back from lms directory and get into cr/user
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const User = require("./../cr/user");
const ContentSchema = new Schema({
type:{
type : String,
required: true
},
users : [{
type : Schema.Types.ObjectId,
ref : "User"
}]
});
const Content = mongoose.model("Content",ContentSchema);
module.exports = Content;
How can I ref user from Content?
i hope your question is clear now. Keep reading below
Moment of truth
Lets insert data by using these two models.
Create a file to write mongo queries (demoproject/index.js).
As User model is nested into Content model, we need to first save data into User model
Then save data into Content model
Now push data into users object present in Content Model contentdata.users.push(userdata);
Donot forget to save the contentdata after pushing the userdata object into contentdata contentdata.save();
demoproject/index.js
const User = require("./cr/user");
const Content = require("./lms/content");
const userobj = new User({name : "rockyjohnson"});
const contentobj = new Content({type : "gloves"});
userobj.save().then((userdata)=>{
contentobj.save().then((contentdata)=>{
contentdata.users.push(userdata);
contentdata.save();
}).catch((err)=>{
console.log("err while saving contentdata ", err);
})
}).catch((err)=>{
console.log("err while saving userdata ", err);
})
Mongodb output
That is all
Update: answer for the second question
find returns an array object in its promise. i'm able to extract users object present inside Content model here. Below is the query i used to verify
Content.find().then((data)=>{
data.forEach(element => {
console.log("element users ",element.users); // element.users contains all id's stored in the users array
});
}).catch((err)=>{
console.log("err ",err);
})

Related

How to save same document in MongoDB?

My Schema
const mongoose = require('mongoose');
const test_schema = new mongoose.Schema({
Name: {
type: String
}
});
const chatting = mongoose.model('chat', test_schema);
module.exports = chatting;
Getting model of above give the schema
const chat = require('./models/chatting.js');
Save Variables
const one = new chat({
Name : "John"
})
const two = new chat({
Name : "John"
})
Now Saving
await chat.insertMany([one, two])
but i got duplicate name key error
You provided a wrong schema to us. (test_schema != chatting_schema). check your chatting schema and see if it is structured somewhat like this:
const chatting_schema = new mongoose.Schema({
Name: {
type: String
unique: true
}
});
if so, remove the unique property.
also, when you already created a document you can just use the .save() function like
await one.save();

How can I match all values nested in a collection to values in another collection (mongodb)?

I am creating a messaging app and I need to be able to display the users with which a given user has conversation history.
I have users and conversations. The models are below. (There is a messages collection where each document refers to a conversation)
//This is the conversation model.
const mongoose = require('mongoose');
const ConversationSchema = new mongoose.Schema({
participants: {
type: Array,
required: true
}
});
const Conversation = mongoose.model('Conversation', ConversationSchema);
//This is the users model (there's more to it, but this is the relevant stuff)
module.exports = Conversation;
const UserSchema = new mongoose.Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
}
});
const User = mongoose.model('User', UserSchema);
module.exports = User;
Each has an _id that is generated.
I am sending an http request with a user ID.
In my controller, using mongoose, I am able to do the following:
Conversation.find({participants:req.params.user_id})
This returns an array of conversation objects, each of which contains a participants array(an array of user IDs).
What I then need to do is match all the participants to the "users" collection so I can get the user ID, first name and last name of each user.
In summary, I need to send an HTTP request with a user ID as a parameter and receive an array of users which have conversation history with the provided user.
What is the next step? How can I match the user IDs I get from the relevant conversations to the user IDs in the users collection?
Try with this
app.post('/:user_id', async(req, res) => {
const partisipant = await Conversation.find({id:req.params.user_id});
const userData = await User.find({id:req.params.user_id});
if(!userData || userData != partisipant){
throw ('no data match')
}
//...if found the data, do anything you want
})
Using async await to get collection data from database, and compare them.
Hope this clue can help you

How to get a list of available Mongoose Discriminators?

Given a situation where you have a User Scheme that you use to create a base model called User. And then for user roles, you use mongoose discriminators to create inherited models called Admin, Employee and Client. Is there a way to programmatically determine how many discriminations/inheritances/roles of the User model are available, as well as the available names?
My question in terms of code:
File: models/user.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var options = {discriminatorKey: 'role'};
var userSchema = mongoose.Schema({
name: String,
email: String,
password: String,
},options);
var User = mongoose.model('User', userSchema);
var Client = User.discriminator("Client", mongoose.Schema({
Address : String,
Tax_identification : String,
Phone_number : String,
Internal_Remarks : String,
CRM_status : String,
Recent_contact : String,
}));
var Employee = User.discriminator("Employee",mongoose.Schema({
Staff_Id: String,
}));
module.exports = {User: User, Client: Client, Employee: Employee };
File: controllers/usersController.js
var User = require('../models/user.js').User;
module.exports = {
registerRoutes: function(app){
app.get('user/create',this.userCreateCallback)
},
userCreateCallback: function(req,res){
//Get Available User Roles - The function below doesn't exist,
//Just what I hypothetically want to achieve:
User.geAvailableDiscriminators(function(err,roles){
res.render('user/create',{roles:roles})
});
}
};
I hope I managed to express what I want to do. Alternative approaches are also welcome.
Since v4.11.13, mongoose model has model.discriminators which is an array of models, keyed on the name of the discriminator model.
In your case if you do console.log(User.discriminators) you will get:
{
Client: {
....
},
Employee: {
}
}
As far as I can see, this is not documented anywhere.
Line 158 in lib.helpers.model.discriminators.js is where this is created.
I think you want to fetch the names and values of all the discriminators as for the names you can simply use
User.discriminators
but for finding values you can use this
return Promise.all(Object.keys(discriminators).map(i =>
discriminators[i].find({ userId: this._id }))
).then(promiseResults =>
promiseResults.reduce((arr, el) => arr.concat(el), [])
);
you need to put userId under each discriminators for that.

Mongoose relations design

I've recently started using Mongoose with Express.js in a Node.js application and I have a question about a proper way to design my schemas.
I have several schemas that have some relationships, i.e. Location schema has an array of Objects (it's not a JS object in this context), and Object schema has its Location property. I've learned that relationships in Mongoose are resolved using population, but when I implemented this approach I noticed that I have to type a lot of duplicate code, i.e. whenever I want to create a new Object I have to also update the Location's array of Objects and then assign the Location to the Object's property. Wouldn't it be more trivial to just manually assemble all the Objects that has a locationId property equal to the Location that I want to get from the database in a separate query?
I have also considered just storing Objects in an array in a Location document (as subdocuments) but I decided that I want to be able to work with Objects (create, remove, update) separately from Locations (without querying a Location) so this approach doesn't fit my needs I guess. But then population has its drawbacks too in my case, so I guess it's really the best to just go with manually collecting Objects of a specific Location in a separate query by that Location's id.
I would like to hear an opinion of some professional or advanced user of this technology on designing Mongoose schemas so that I and others don't get into trouble later maintaining and scaling our applications.
Here are my current schemas in question:
var locationSchema = new mongoose.Schema({
title: String,
objects: [{ type: String, ref: 'object' }]
});
var objectSchema = new mongoose.Schema({
title: String,
location: { type: String, ref: 'location' }
});
Checkout this example
db/schemas.js:
const Schema = mongoose.Schema;
const ObjectSchema = {
title: Schema.Types.String
}
const LocationSchema = new Schema({
title: Schema.Types.String,
objects: [{type: Schema.Types.ObjectId, ref: 'Object'}]
})
module.exports = {
Object: ObjectSchema,
Location: LocationSchema
};
db/model.js:
const
mongoose = require('mongoose'),
schemas = require('./schemas');
module.exports = model => mongoose.model(model, schemas[model+'Schema']);
usage:
const
model = require('./db/model'),
LocationModel = model('Location');
LocationModel
.findOne({_id: 'some id here'})
.populate('objects')
.exec((err, LocationInstance) => {
console.log(LocationInstance.title, ' objects:', LocationInstance.objects);
});
when You create an object and want to relate to location:
const
model = require('./db/model'),
ObjectModel = model('Object'),
LocationModel = model('Location');
let
ObjectInstance = new ObjectModel({title: 'Something'});
ObjectInstance.save((err, result) => {
LocationModel
.findByIdAndUpdate(
'some id here',
{$push: {objects: ObjectInstance._id}},
(err) => {
console.log('Object:', ObjectInstance.title, ' added to location');
});
});
updating object data:
const
model = require('./db/model'),
ObjectModel = model('Object');
let id = 'id of object';
ObjectModel
.findByIdAndUpdate(
id,
{title: 'Something #2'},
(err) => {
console.log('Object title updated');
});
finding location by object:
const
model = require('./db/model'),
LocationModel = model('Object');
let id = 'id of object';
LocationModel
.findOne({objects: id})
.populate('objects')
.exec((err, LocationInstance) => {
console.log('Location objects:', LocationInstance.objects);
});
nothing special findOne({objects: id}) will search inside location documents that has relation by id in objects array
any other question welcome (:

Mongoose - inserting subdocuments

I have a user model, and a log model. The log model is a subdocument of user model. So in my user model I have:
var mongoose = require('mongoose');
var Log = require('../models/log');
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [
Log
]
});
Then in my 'Log' model I have:
var mongoose = require('mongoose');
var logSchema = new mongoose.Schema({
logComment: {
type: String,
},
});
module.exports = mongoose.model('Log', logSchema);
So upon creation of a 'user', the 'logsHeld' always begins empty. I want to know how to add subdocuments to this user model.
I've tried doing this POST method:
router.post('/createNewLog', function(req, res) {
var user = new User ({
logssHeld: [{
logComment: req.body.logComment
}]
});
user.save(function(err) {
if(err) {
req.flash('error', 'Log was not added due to error');
return res.redirect('/home');
} else {
req.flash('success', 'Log was successfully added!');
return res.redirect('/home');
}
});
});
But this doesn't work. It also includes a 'new User' line, which I don't think I need given this would be for an existing user.
You need to use the logSchema instead of the Log model as your subdocument schema in User model. You can access the schema as follows:
var mongoose = require('mongoose');
/* access the Log schema via its Model.schema property */
var LogSchema = require('../models/log').schema; // <-- access the schema with this
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [LogSchema]
});
Picking up from your comments in another answer where you are facing another issue
WriteError({"code":11000,"index":0,"errmsg":"E11000 duplicate key
error index: testDB.users.$email_1 dup key:
you are getting this because there's already a document in your users collection that has most probably a null value on the email field. Even though your schema does not explicitly specify an email field, you may have an existing old and unused unique index on users.email.
You can confirm this with
testDB.users.getIndexes()
If that is the case and manually remove the unwanted index with
testDB.users.dropIndex(<index_name_as_specified_above>)
and carry on with the POST to see if that has rectified the error, I bet my $0.02 that there is an old unused unique index in your users collection which is the main issue.
Try using logSchema which references only the subdocument schema, Log refers to the entire contents of ../models/log
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [
logSchema
]
});
Documentation: http://mongoosejs.com/docs/subdocs.html
Try push to insert item in array in mongoose
var user = new User;
user.logssHeld.push({
logComment: req.body.logComment
});
user.save(function(err, doc) {
//DO whatever you want
});
see the docs here

Resources