mongoose find by ObjectId - node.js

I'm defining a mongoose schema like this
var accountPostSchema = new mongoose.Schema({
account: {
id: { type: mongoose.Schema.Types.ObjectId, ref: 'Account' }
},
post: {
id: { type: mongoose.Schema.Types.ObjectId, ref: 'Post' }
}
});
app.db.model('AccountPost', accountPostSchema);
When a user(account holder) create a post, I save the post in a Post schema and get the 'postId'. Then I save the 'postId' and the 'accountId'
in the above accountPostSchema like this
var fieldsToSet = {
post: {
id: postId
},
account: {
id: accountId
}
};
db.models.AccountPost.create(fieldsToSet, function(err, accountPost) {
if (err) {
// handle error
}
// handle success
});
After entering few postId's and accountId's, I see the following results in the mongo shell
> db.accountposts.find({})
{ "_id" : ObjectId("5835096d63efc04da96eb71e"), "post" : { "id" : ObjectId("5835096d63efc04da96eb71d") }, "account" : { "id" : ObjectId("5833c920c868d7264111da69") }, "__v" : 0 }
{ "_id" : ObjectId("583509e12052c7a2a93c4027"), "post" : { "id" : ObjectId("583509e12052c7a2a93c4026") }, "account" : { "id" : ObjectId("5833c920c868d7264111da69") }, "__v" : 0 }
Now how do I find all the matching 'Posts' given an accountId? (not the postId's)
For example if I the accountId is 583509e12052c7a2a93c4026, I need to find Posts with Post._id=5835096d63efc04da96eb71d and Post._id=583509e12052c7a2a93c4026
What is the query I should run to get the matching Posts?

I think, you should follow this way to get all the posts associated with particular accountid.
db.accountposts.find({'account.id' : accountId})
.populate('post.id')
.exec();

First, I would suggest changing your Schema to the following
var accountPostSchema = new mongoose.Schema({
account: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Account'
},
post: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}
});
This actually makes more sense, especially when you try to populate the subdocuments. Actually, I would say this Schema is useless. Why don't you define your Post schema like the following?
var PostSchema = new mongoose.Schema({
poster: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Account'
},
message: String
});
If you use the latter code, you could execute the following query to get all posts by a particular user:
db.posts.find({poster: accountId}, function(dbErr, userPosts) {
if(dbErr) {
// Handle the error.
}
// Do something with the posts by accountId in the array userPosts.
});
The advantages of removing the id field from poster becomes clear once you try to populate poster. If you defined poster as an object with the field id and try to populate it, you will need to access data about the poster as such:
posterName = retrievedPost.poster.id.name;
Alternatively, by just making the poster field an ObjectId directly, you can access the populated user more directly:
posterName = retrievedPost.poster.name;

Related

MongoError: Cannot apply $addToSet to non-array field. Field named 'trackTime' has non-array type string

Here i'm trying to update with the userid, trackTime fields. Evertime userid and trackTime will be different so i'm using $addToSetbut here i'm facing an error
like this i'm passing the data in postman:-
{
"courseId":"61001184afeacb22ac1668e0",
"userId":"60f6fe96a1a44a1fb4a59573",
"trackingTime":"4"
}
this is the schema:-
usersEnrolled : [{
iscourseenrolled : { type:Boolean, default: false },
userId: {type: String },
trackTime: {type:String}
}],
code:-
const updatedTrackTime = await Courses.updateOne({ "_id" : req.body.courseId},{
$addToSet:{
"usersEnrolled.0.userId" : req.body.userId,
"usersEnrolled.0.trackTime": req.body.trackingTime
}})
The reason for that error is probably because you didn't specify the array field (Actually you didn't specify any field at all). Try to add your usersEnrolled field like this:
const updatedTrackTime = await Courses.updateOne({ "_id" : req.body.courseId},{
$addToSet:{
usersEnrolled: {
"usersEnrolled.0.userId" : req.body.userId,
"usersEnrolled.0.trackTime": req.body.trackingTime
}
}});
To get more details on $addToSet use MongoDB Manual
https://docs.mongodb.com/manual/reference/operator/update/addToSet/
I just changed in to these and it worked for me
const updatedTrackTime = await Courses.updateOne({ "_id" : req.body.courseId},{ $addToSet:{
usersEnrolled : {
userId : req.body.userId,
trackTime: req.body.trackingTime
}

Response output not showing entire information present in mongoose schema nodejs

I have designed a Mongoose schema like this :
const metricsSchema = mongoose.Schema({
_id : mongoose.Schema.Types.ObjectId,
level : String,
details: {
demo: String,
full: String
}
});
Also, I have handled the response as such :
router.post('/',(req, res, next)=>{
const metrics = new Metrics({
_id : new mongoose.Types.ObjectId(),
level : req.body.level,
details:{
demo: req.body.demo,
full: req.body.full
}
});
res.status(201).json({
metrics: metrics
})
});
However, when I use Postman to post JSON data like this :
{
"level" :"schema" ,
"details":{
"demo" : "2465",
"full" : "1211234"
}
}
I get output like this :
{
"metrics": {
"_id": "5e09c156b0ce8a4a54a3ecca",
"level": "schema"
}
}
I do not get the rest of the output : demo and full in the response json. I wish to get the output like this :
{
"metrics": {
"_id": "5e09c156b0ce8a4a54a3ecca",
"level": "schema"
"details": {
"demo": "2465",
"full": "1211234"
}
}
}
Update: I found one solution in which the Mongoose schema was divided into two parts :
const detailsSchema = mongoose.Schema({
_id : mongoose.Schema.Types.ObjectId,
demo: String,
full: String
});
mongoose.model('Details',detailsSchema );
const metricsSchema = mongoose.Schema({
_id : mongoose.Schema.Types.ObjectId,
level : String,
details: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Details'
}
});
However, this did not work as well.
You have to change the code as below:
router.post('/',(req, res, next)=>{
const metrics = new Metrics({
_id : new mongoose.Types.ObjectId(),
level : req.body.level,
details:{
demo: req.body.details.demo, <----- see the change here
full: req.body.details.full
}
});
res.status(201).json({
metrics: metrics
})
});

Save multiples Objects At Once Mongo(Many To Many Mongoose)

this is my scene:
I have 2 collections(tables):Projects and students(the relation is many to many).
My models are:
Project:
var ProjectSchema = new Schema({
name: {
type: String
},
description: {
type: String
},
user : {
type : Mongoose.Schema.Types.ObjectId,
ref : "User"
}
});
Mongoose.model('Project', ProjectSchema);
User:
var Userchema = new Schema({
name: {
type: String
},
surname: {
type: String
},
project : {
type : Mongoose.Schema.Types.ObjectId,
ref : "Project"
}
});
Mongoose.model('User', UserSchema);
In my view I have 2 inputs where receive name and description of project, then have multiselect where choose 1 or multiples users for this project. When I Click OK should:
Create project, and add to user all users selected as objects in BBDD.
Update user, with project asociation.
I try the next, but only funcion if I choose 1 user:
exports.addUserProject = function(req, res) {
var project=new svmp.Project();
project.name=req.body.name;
project.description=req.body.description;
project.user=req.body.user[0]._id;
project.save(function(err,project){
if (err) {
return res.send(400, {
message : getErrorMessage(err)
});
} else {
res.jsonp(project);
}
})
};
The result in my BBDD is the next:
{ "_id" : ObjectId("57a200a38fae140913ac5413"), "user" : ObjectId("578f41ddb0641d961416c3f5"), "name" : "Project1", "Description" : "Project1 Desc","__v" : 0 }
Thanks for your help
First in your schema definition, since the relationship is many-to-many, you should change the ref to an array of the referenced objects. For example change the user property of projectSchema to an array of object ids like so,
var ProjectSchema = new Schema({
name: {
type: String
},
description: {
type: String
},
user : [{
type : Mongoose.Schema.Types.ObjectId,
ref : "User"
}]
});
Do the same for the project property of the userSchema.
Secondly, on this line project.user=req.body.user[0]._id; you are setting the the _id of only the first selected user as the user while ignoring every other selected users. This is why your code only works for one user. Instead, I will suggest you use a simple loop to push all selected users' _id to the project's user property. You can use a forEach loop as given below.
var selectedUsers = req.body.user;
selectedUsers.forEach(function(u){
project.user.push(u._id)
})
You can also do this with a simple for loop if you wish.
I believe the suggestions above should fix the issues you described.

mongodb mongoose nodejs express4 why insert a _id in Object Array field automatically?

It might be conceptual question about _id in mongodb.
I understand mongodb will insert a _id field automatically if you don't set key field in document.In my case, I defined a field as Object Array, I don't know why it always create a _id in each Object in Array of this field.
I do appreciate if someone could clarify it for me.
Mongoose Model Scheme definition:
module.exports = mongoose.model("Application", {
Name: String,
Description: String,
Dependency: [
{
App_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Application'
},
Priority: Number
}
]
});
This is an Update operation, request data is:
{ _id: '571953e33f33c919d03381b5',
Name: 'A Test Utility (cmd)',
Description: 'A Test Utility (cmd)'
Dependency:
[ { App_id: '571953e33f33c919d03381b6', Priority: true },
{ App_id: '571953e33f33c919d03383da', Priority: 0 } ]
}
I use this code to update it
var id = req.body._id;
Application.findOneAndUpdate({ _id: id }, req.body, function (err, app) {
if (err)
res.send(err);
res.json(app);
});
The update is successful.But the document in mongodb is:
{
"_id" : ObjectId("571953e33f33c919d03381b5"),
"Name" : "A Test Utility (cmd)",
"Description" : "A Test Utility (cmd)",
"Dependency" : [
{
"Priority" : 1,
"App_id" : ObjectId("571953e33f33c919d03381b6"),
"_id" : ObjectId("571a7f552985372426509acb")
},
{
"Priority" : 0,
"App_id" : ObjectId("571953e33f33c919d03383da"),
"_id" : ObjectId("571a7f552985372426509aca")
}
]
}
I just don't understand how come the _id in the "Dependency" Array?
Thanks.
When you use [{..}] that means inside it act as a sub schema and you know that MongoDB insert a _id field automatically if you don't set key field in document. So you need to force to insert document without _id field.
Need use {_id:false} for your Dependency array schema to insert without _id
var ApplicationSchema = new mongoose.Schema({
Name: String,
Description: String,
Dependency: [
{
App_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Application'
},
Priority: Number,
_id: false
}
]
});
module.exports = mongoose.model("Application", ApplicationSchema);

Mongoose fail to set ref -Schema.Types.ObjectId- to other document

I'm trying to save a document with mongoose according to the doc http://mongoosejs.com/docs/populate.html
First I call parent.save and inside the callback of parent.save I use child.save.
But when I check parent.childs I can see that no child has been added.
The parent schema is Home :
var HomeSchema = new Schema({
password : String,
draft : { type: Boolean, default: true },
edited : { type: Boolean, default: false },
guests : [{type : Schema.Types.ObjectId, ref : 'Guest'}],
_event : {type : Schema.Types.ObjectId, ref : 'Event'}
});
the child schema is Guest :
var GuestSchema = new Schema({
_home : {type : Schema.Types.ObjectId, ref : 'Home'},
firstname : String,
lastname : String,
coming : { type: String, default: 'dnk-coming' },
phone : String,
email : String,
address : String,
edited : { type: Boolean, default: false },
draft : { type: Boolean, default: true }
});
To avoid any misunderstanding, you have to know that this two Schema are included in my user schema :
var userSchema = mongoose.Schema({
homes:[homeSchema.HomeSchema],
events:[eventSchema.EventSchema],
guests:[eventSchema.guestSchema],
});
Now you should have all the required informations to completly understand the execution :
UserModel.findById(user._id, function(err, userFound) {
if (!err) {
/* cleaning draft*/
userFound.homes = that.clean(userFound.homes);
/* setting draft */
var HomeModel = mongoose.model("Home");
var homeModel = new HomeModel();
homeModel.draft = true;
if (userFound.homes === null) {
userFound.homes = [];
}
homeModel.save(function(err) {
if (!err) {
var GuestModel = mongoose.model("Guest");
var guestModel = new GuestModel();
guestModel._home = homeModel._id;
guestModel.save(function(err) {
if (!err) {
// #ma08 : According to the doc this line should'nt be required
//homeModel.guests.push(guestModel._id); so when I use this obviously the id is correctly set but when I try a populate after saving the populate do not work
userFound.homes.push(homeModel);
userFound.guests.push(guestModel);
userFound.save(function(err) {
if (!err) {
successCallback();
}
else {
errorCallback();
}
});
}
});
}
});
This treatement doesn't result in any error. But it doesn't work as intended when I stringify the user.guests I get :
guests:
[ { coming: 'dnk-coming',
edited: false,
draft: true,
_id: 53dcda201fc247c736d87a95,
_home: 53dce0f42d5c1a013da0ca71,
__v: 0 }]
wich is absolutly fine I get the _home id etc...
Then I stringify the user.homes and I get :
homes:
[ { draft: true,
edited: false,
guests: [],
_id: 53dce0f42d5c1a013da0ca71,
__v: 0 } ]
According to the doc guests should be setted, but it's not <-- this is my issue. Please help me to figure out what I'm doing wrong. I could set it manualy but according to the doc it's not suppose to work this way I think.
guestModel.save(function(err) {...
this is wrong because you are embedding the guests in the userSchema.
So skip the guestModel.save and just push the guestModel in userFound
An embedded document can never a reference. You can't point to it without obtaining the parent document. So you can't do both embedding and keeping a ref to the embedded document. You should choose between either embedding or adding a ref.
My suggestion would be to design your schemas like this. Store guests in a separate collection. Store the ref to guest in user and home schemas. If you want to store some relationship data you can store along with the ref like [{guestId:{type:Schema.Types.ObjectId,ref:'Guest'},field1:{type:...},field2:{...}..] and if you just want the ref [{type:Schema.Types.ObjectId,ref:'Guest'}]

Resources