How we reference mongodb using populate method using node js - javascript

I have doing referencing using the populate method in node js , but I have no more idea about the populate method. In this code, i am a reference to user collection from my child collection. I have two collections one child and second user
This child collection
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
index: true
}
This is user collection
"firstname":{type:String},
"lastname":{type:String}
I have send id from URL (http://localhost:8000/v1/childPopulate/:57a4e4e67429b91000e225a5) and queried with my stored userId in child schema
This is node js
this.childPopulate = function(req, res, next){
var o_userid = req.params.id;
var query = {userId:o_userid};
Child.findOne(query).populate({
path: 'userId',
model: 'User',
select: 'firstname lastname'
}).exec(function(err,userinfo){
if(err){
return next(err);
}else{
res.send(userinfo);
console.log(userinfo);
}
});
};
But this shows this error in browser
{"message":"Cast to ObjectId failed for value \":57a4e4e67429b91000e225a5\" at path \"userId\""}

The error message indicates that you are passing a string instead of ObjectID.
Basically the default id in mongodb is not a normal string.
Its is a unique 12-byte identifier.
So you should convert the string to type ObjectID.
var query = {userId: mongoose.Types.ObjectId(stringId)};

Related

Mongoose - Deleting documents is unresponsive

I'm trying to use Mongoose (MongoDB JS library) to create a basic database, but I can't figure out how to delete the documents / items, I'm not sure what the technical term for them is.
Everything seems to work fine, when I use Item.findById(result[i].id), it returns a valid id of the item, but when I use Item.findByIdAndDelete(result[i].id), the function doesn't seem to start at all.
This is a snippet the code that I have: (Sorry in advance for bad indentation)
const testSchema = new schema({
item: {
type: String,
required: true
},
detail: {
type: String,
required: true
},
quantity: {
type: String,
required: true
}
})
const Item = mongoose.model("testitems", testSchema)
Item.find()
.then((result) => {
for (i in result) {
Item.findByIdAndDelete(result[i].id), function(err, result) {
if (err) {
console.log(err)
}
else {
console.log("Deleted " + result)
}
}
}
mongoose.connection.close()
})
.catch((err) => {
console.log(err)
})
I'm not sure what I'm doing wrong, and I haven't been able to find anything on the internet.
Any help is appreciated, thanks.
_id is a special field on MongoDB documents that by default is the type ObjectId. Mongoose creates this field for you automatically. So a sample document in your testitems collection might look like:
{
_id: ObjectId("..."),
item: "xxx",
detail: "yyy",
quantity: "zzz"
}
However, you retrieve this value with id. The reason you get a value back even though the field is called _id is because Mongoose creates a virtual getter for id:
Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field cast to a string, or in the case of ObjectIds, its hexString. If you don't want an id getter added to your schema, you may disable it by passing this option at schema construction time.
The key takeaway is that when you get this value with id it is a string, not an ObjectId. Because the types don't match, MongoDB will not delete anything.
To make sure the values and types match, you should use result[i]._id.

Mongoose : Cast to ObjectId failed for value "Some String" at path "_id"

New to MongoDB, Javascript stack and need help understanding cause of this error.
I have my model created :
const
Mongoose = require('mongoose');
Schema = Mongoose.Schema,
Model = Mongoose.model;
module.exports = Model('Project',
new Schema({
icon : String,
name : String,
state : String,
number : String
})
);
This is my MongoDB document :
[![MongoDB Document][1]][1]
I am attempting to receive all the documents in the collection when I call the API so therefore as per the Mongoose document I am using the find() method.
Here is my API Implementation:
const Project = require('../../models/project');
router.get('/projects/:page?/:limit?',
function(req, res, next){
const page = Math.max(req.params.page || 1, 1) - 1;
const limit = Math.max(req.params.limit || 20, 20);
//Verified : I am hitting the API
console.log("Reached API /projects");
Project.find()
.populate('icon')
.populate('name')
.populate('state')
.populate('number')
.limit(limit).skip(page * limit).exec(
function(err, project)
{
if (err) { return next(err); }
res.send(project);
}
); //End of exec()
}//End of unction
);
I am successful in making the API call using fetch() but I am receiving "Cast to ObjectId failed error" for all the String values.
I believe there is something really simple within my Mongo DB document that I might be missing. Please help me understand and solve this issue.
**EDIT ---
The error seems to point at the string values of the keys:
**
Thank you
Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). So you're Id cast is not valid, because of string, you need to have ObjectId, some changes need to be made before it, Let's debug:
const alldata = await Project.find()
console.log(alldata) // ?
does this return something, I'm using async await here if it return data then the problem is with your populate because your Id case isn't valid as you save in schema string and you're referring here populate, example of using populate:
module.exports = Model('Project',
new Schema({
icon : [{ type: Schema.ObjectId, ref: 'your icon document' }],
name : [{ type: Schema.ObjectId, ref: 'you name document' }],
state : [{ type: Schema.ObjectId, ref: 'state document' }],
number : [{ type: Schema.ObjectId, ref: 'number document' }]
})
);
but it seems to me that you don't need to use the populate because you have simple data, name, number... so you should be good to go with the above example
Resources: mongoose fetching data, using populate, relation

Mongoose auto fill data by searching in reference

const UserSchema = new Schema(
{
referrals: {
ref: 'User',
type: [mongoose.Schema.Types.ObjectId],
},
referredBy: {
ref: 'User',
type: mongoose.Schema.Types.ObjectId,
},
}
);
I want Mongoose to find users who have current user _id in referredBy reference.
In other words, eg: find all users who have '_IDOfSpecificUser' in their referredBy field and put all the found users in the array of referrals where user's _id is '_IDOfSpecificUser'.
How can I handle that in mongoose?
Simplest is using find
User.
find({ "referredBy" : "xxxxxxxxxxxx" }).
exec(function (err, users) {
if (err) return handleError(err);
console.log('The users are an array: ', users);
});
Refer to https://mongoosejs.com/docs/populate.html
If you want to convert bellow function to static method inside UserSchema, please refer to this https://mongoosejs.com/docs/api.html#schema_Schema-static and https://mongoosejs.com/docs/2.7.x/docs/methods-statics.html

Populating an Object with Information from a Child Object with Different Model (JS/Mongoose)

Here is what I have. I created a project model that references a user model for an array of members.
var ProjectSchema = new mongoose.Schema(
{title: {
type: String,
required: true
},
members: [
{user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'users'
}
}],
});
User Schema (I have code that creates a model from both of these schemas)
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
}
});
In a separate file, I want to export the JSON of a found project and include the information of the users in the members array, but I am not sure how to do that. This is the code I have right now.
const project = await Project.findById(req.params.proj_id).populate(
'members'
);
res.json(project);
It has no trouble finding the project but the only information I can get on the members is their id. I tried using for loops to gather the information from members separately using the id that I can get from the project, but the code gets messy and I am hoping to find a simpler way to do it.
You can use mongoose populate query to get all members associated with a project. It should populate array of objects users associated to a project. You should be doing something like this:
const project = await Project.findById(req.params.proj_id)
await project.populate('members').execPopulate()
console.log(project.members)
Mongoose docs for the reference: Populate
You can give the model to your mongoose populate.
const project = await Project.findById(req.params.proj_id)
.populate({
'members',
model: UserModel
})
.exec()
res.json(project);
keep in mind you've to create UserModel just like
const UserModel = mongoose.model('User', userSchema);

Mongoose request for id field returns id and _id

In my Mongoose schema I have an id field which has a unique ID for each document. This runs off the same system used by the default _id field like so:
var JobSchema = new mongoose.Schema({
id: { type:String, required:true, unique:true, index:true, default:mongoose.Types.ObjectId },
title: { type: String },
brief: { type: String }
});
module.exports = mongoose.model("Job", JobSchema);
Now, if I query the schema to get id and title I'd do it like this:
Job.find().select("id title").exec(function(err, jobs) {
if (err) throw err;
res.send(jobs);
});
However, I've found this returns id and title as expected, but it also return the default _id field. Why is that and how do I stop it?
Inside the find() function you can pass two parameters (criteria and projection). Projection are the fields that you want (or not). In your case you can change your code to
Job.find({}, {_id:0, id: 1, title: 1}, function(err, jobs) {
if (err) throw err;
res.send(jobs);
});
and it should do it.
There is an option to prevent the id on schema level.
For me this worked perfectly fine.
new Schema({ name: String }, { id: false });
Mongoose Docs

Categories