Populate doesn't work Mongoose (no database insertion) - node.js

I've got a big problem, i'm trying to use model associations in Mongoose because it would be really useful but there's something i don't get ...
Let's say there's a User model with a schema like ... (among others)
user_geos : [{
type: Mongo.Schema.ObjectId,
ref: 'UserGeo',
}]
And there's a UserGeo model with this schema ... (among others)
_user: {
type: Mongo.Schema.ObjectId,
ref: 'User'
}
Very simple, when I'm creating a new UserGeo, it should automatically add it to the user_geos array within User, right ?
user_geo_infos._user = user.id;
db.UserGeo.create(user_geo_infos, function(error, user_geo) {
catches.error(error);
console.log(user_geo);
});
The big problem I got is when i'm creating it, it fills correctly the "_user" field in UserGeo in the database but the User model doesn't fill itself. The array stay empty ("[]"). A detail but you really understood is UserGeo got one User and User got many UserGeo.
I'm really stuck, did i do something wrong ? I checked everywhere and read the Mongoose documentation like 10 times now ...
Any idea ? Thanks people ;)

Very simple, when I'm creating a new UserGeo, it should automatically add it to the user_geos array within User, right ?
Nope. There is a lot less magic/automatic stuff here than you are hoping for. Mongodb, as well as mongoose, will only ever act upon a single collection at a time. This will do the querying automatically when you load records and use the mongoose .populate helper, but it doesn't help you writing across collections.

Ok I tried to make it manually and it works but i'm quite disappointed ... Looks like this ...
db.UserGeo.create(user_geo_infos, function(error, user_geo) {
db.User.findOne(user.id, function(error, user) {
catches.error(error);
user.user_geos.push(user_geo.id);
user.save();
});
catches.error(error);
console.log(user_geo);
});
After I create a UserGeo I get the User and then push the new data to the User field ...
This is solution is heavy, maybe make some helpers would make it lighter .. Thanks anyway :)

Related

Updating Particular field in Nodejs

I wanted to update the field data only ,but my code it adding an object each time i am calling update api.I have gone through many sites and found out updateOne is the method but couldnt end up undersatnding how to implement here.I am quite new to node so any help would be appreciated.
const update=(req,res)=>{
console.log(req);
models.detailsSchema.findByIdAndUpdate(req.body.vehicleId,req.body.data,{new:true}).then((msg,err)=>{
if(err)
res.status(400).json({err})
res.status(200).json({
"resCode":"0000",
"resStatus":"Success",
"resMsg":msg
})
});
}
Looks like you're using Mongoose connected to a MongoDB instance? If that's the case, Schema.findByIdAndUpdate works on the primary key or ObjectId of the record you're trying to update. To make this code work, if my assumptions are correct, change to this:
models.detailsSchema.findByIdAndUpdate(req.body._id, req.body.data, { new:true })
Of course, you're going to want to put in some check to make sure _id is defined if this is a create/update route.

Sequelize update with associations

I have two models which user and merchant. I will send JSON data from UI.
In Sequelize, I have used "include" option to insert the data like below.
models.user.create(req.body, { include: [models.merchant] });
It is working well as expected. So I have tried to update the data like below.
var filter = {
where: { id: id },
include: [
models.merchant
]
};
models.user.update(req.body, filter);
The above code is updating user data only. Association is not working in the update. I don't know what is wrong with this.
Please anyone help to resolve this issue.
Thanks in advance.
The behaviour your asking for simply can't be done with a single update call. If you check the docs for the update function, there isn't an include option, i.e. sequelize can only build an update query for the table of the model who's update function is called.
You will have to update the associations separately. I advise that you put those updates inside a transaction to avoid any issues with multiple updates to the same object happening at the same time.

MongoDB and Mongoose - One to Many Relationships

I'm having a devil of a time understanding the one to many relationship options in MongoDB. I have a fairly simple use-case that I want to prove out, and I can't seem to find any good step-by-steps with my Google (and Stack Overflow)-Fu.
If I access mongo's command line tool, insert a document into the "users" collection with a String array of role_id that corresponds to the _id in the "roles" collection ... how do I tie all of it together on the mongoose side? When I use the findOne method, it just seems to pull the "role_id"s as is, so I know I must be missing something.
If I put all of these roles into the users without any reference what so ever, what happen if I needed to enable or disable roles? Would I need to update every single relevant role in every single user?
Thanks muchly for the assistance and patience for another new Mongoer!
According to your explanation you just forgot to use 'populate' in your query. Please note that results will not contain linked document, so you need to use 'populate' in order to let mongoose know - 'Hey, I want to pull info about this role as well'.
Example:
//promises
User
.findOne(<searchQuery>)
.populate('roles')
.exec()
.then(function(foundUser){
return foundUser; //do something with results (foundUser)
})
.onReject(function(err){
throw err; //do something with error
});
//callbacks
User
.findOne(<searchQuery>)
.populate('roles')
.exec(function(err, foundUser){
if(err){
throw err; //do something with error
} else {
//do something with results (foundUser)
}
});
Please check the following links:
http://mongoosejs.com/docs/2.7.x/docs/populate.html
http://mongoosejs.com/docs/populate.html

using _.omit on mongoose User in node.js

I have a mongoose User schema built like this:
var UserSchema = new Schema({
username: { type: String, required: true, index: { unique: true } },
password: { type: String, required: true },
salt: { type: String, required: true}
});
I want to be able to send this user object to the client side of my application but I don't want to sned the password or salt fields.
So I added he following code to my user model module
U
serSchema.methods.forClientSide = function() {
console.log('in UserSchema.methods.forClientSide');
console.log(this);
//var userForClientSide=_.omit(this,'passsword','salt');
var userForClientSide={_id:this._id, username:this.username };
console.log(userForClientSide);
return userForClientSide;
}
I have required the underscore module (its installed locally via a dependency in my package.js).
not the commented out line - I was expecting it to omit the password and salt fields of the user object but it did not do anything :( the logged object had the full set of properties.
when replaced with the currently used like var userForClientSide={_id:this._id, username:this.username }; it gets the results I want but:
1) I want to know why does the _.omit not work.
2) I don't like my current workaround very much because it actually selects some properties instead of omitting the ones I don't like so if I will add any new propertes to the scema I will have to add them here as well.
This is my first attempt at writing something using node.js/express/mongodb/mongoose etc. so It is very possible hat I am missing some other better solution to this issue (possibly some feature of mongoose ) feel free to educate me of the right way to do things like this.
so basically I want to know both what is the right way to do this and why did my way not work.
thanks
1) I want to know why does the _.omit not work.
Mongoose uses defineProperty and some heavy metaprogramming. If you want to use underscore, first call user.toJSON() to get a plain old javascript object that will work better with underscore without all the metaprogramming fanciness, functions, etc.
A better solution is to use mongo/mongoose's fields object and pass the string "-password -salt" and therefore just omit getting these back from mongo at all.
Another approach is to use the mongoose Transform (search for "tranform" on that page). Your use case is the EXACT use case the documentation uses as an example.
You can also make your mongoose queries "lean" by calling .lean() on your query, in which case you will get back plain javascript objects instead of mongoose model instances.
However, after trying each of these things, I'm personally coming to the opinion that there should be a separate collection for Account that has the login details and a User collection, which will make leaking the hashes extremely unlikely even by accident, but any of the above will work.

Node.js + Mongoose / Mongo & a shortened _id field

I'd like the unique _id field in one of my models to be relatively short: 8 letters/numbers, instead of the usual Mongo _id which is much longer. Having a short unique-index like this helps elsewhere in my code, for reasons I'll skip over here. I've successfully created a schema that does the trick (randomString is a function that generates a string of the given length):
new Schema('Activities', {
'_id': { type: String, unique: true, 'default': function(){ return randomString(8); } },
// ... other definitions
}
This works well so far, but I am concerned about duplicate IDs generated from the randomString function. There are 36^8 possible IDs, so right now it is not a problem... but as the set of possible IDs fills up, I am worried about insert commands failing due to a duplicate ID.
Obviously, I could do an extra query to check if the ID was taken before doing an insert... but that makes me cry inside.
I'm sure there's a better way to be doing this, but I'm not seeing it in the documentation.
This shortid lib https://github.com/dylang/shortid is being used by Doodle or Die, seems to be battle tested.
By creating a unique index on _id you'll get an error if you try to insert a document with a duplicate key. So wrap error handling around any inserts you do that looks for the error and then generates another ID and retries the insert in that case. You could add a method to your schema that implements this enhanced save to keep things clean and DRY.

Resources