ObjectId doesn't find ObjectId - node.js

My database has the following data:
db.users.find()
{ "_id" : ObjectId("5580c79aa11e7310b2985ab1"), "email" : "an_email", "color" : "", "username" : "", "__v" : 0 }
I query it with Mongoose using the following syntax:
User.findById("5580c79aa11e7310b2985ab1", function(error, user) { }
which returns null for both error and user. Strangely enough Mongoose's debugging shows the following, correct query:
users.findOne({ _id: ObjectId("5580c79aa11e7310b2985ab1") })
which directly queried on MongoDB finds the expected data:
db.users.findOne({ _id: new ObjectId("5580c79aa11e7310b2985ab1") })
{
"_id" : ObjectId("5580c79aa11e7310b2985ab1"),
"email" : "an_email",
"color" : "",
"username" : "",
"__v" : 0
}
Replacing findById with findOne and looking for email works. I really have no idea anymore... Any suggestions?

findById() expects an id, not an object. Example:
Book.findById(req.user.id, function(err, book) {...}
findOne() expects an object so it works.

Seems it is a bug with Mongoose 4.x - I reverted back to Mongoose 3.8 and everything works fine.

Related

$pull is not working for array in mongoose (MongoDB)

In mongoDB (Through mongoose), I am trying to remove an element in array of a collection and using $pull operator for that, but it is not working.
Rooms collection in mongoDB
{
"_id":"sampleObjectId",
"users": ["email1#example.com", "email2#example.com"]
}
Backend code to remove a user (mongoose using Node.js)
Rooms.update(
{ _id: "sampleRoomId" },
{
$pull: {
users: "email1#exmple.com" }
},
}
)
Noting happens to collection on running this code, no change happens. code runs with no errors and in output it says "nModified":0 .
I have no idea how to remove a user from collection.
//actual code output from the mongo shell. This is working as expected. check if you given //correct value in object_id query parameter.
> db.rooms.find();
{ "_id" : "sampleObjectId", "users" : [ "email1#example.com", "email2#example.com" ] }
> db.rooms.update(
... {_id: "sampleObjectId"},
... {$pull:{users:"email1#example.com"}}
... );
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.rooms.find();
{ "_id" : "sampleObjectId", "users" : [ "email2#example.com" ] }
> db.version();
4.2.6
>

console.logging data from MongoDB

I am still trying to comprehend Mongoose/Mongo
Now in terminal When I do something like this in terminal
use library
show collections
db.authors.find().pretty()
I get something like this in logged
{
"_id" : ObjectId("5bc8704f3a9828d5513505a2"),
"name" : "Aman",
"age" : "21",
"__v" : 0
}
{
"_id" : ObjectId("5bc870553a9828d5513505a3"),
"name" : "Rohit",
"age" : "20",
"__v" : 0
}
{
"_id" : ObjectId("5bc8704f3a9828d5513505a7"),
"name" : "Aman",
"age" : "21",
"__v" : 0
}
{
"_id" : ObjectId("5bc870553a9828d5513505a5"),
"name" : "Rohit",
"age" : "20",
"__v" : 0
}
Now, I want to have same data in my NodeJs i.e say, I want to find wherever the name is Rohit and want to link it with with some other db or schema.
how can I get the same output which I just obtained by running the above given command in terminal window of mongo in NodeJS
Obviously doing something like this console.log(db.authors.find()) won't work, so how can I get that?
This is how I usually write my database queries.
First create a schema that your model will follow. Don't worry this schema is flexible and you can change it at any time without affecting old data.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var authorSchema = new Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
default: 20
}
});
Next create a model from your schema.
var authorModel = mongoose.model('authorModel', authorSchema);
Lastly query your model and get the value you need
authorModel.find(
{
name: 'Rohit'
},
function (err, result) {
console.log(result)
});
I put my schema and controller on separate files. How you organise your code structure is up to you.
I pretty much followed this blog when I first learnt to build APIs on NodeJS. You might find this useful as well!

MongoDB/Mongoose $inc subdocument does not modify anything

I am trying to update a subdocument inside of an array.
{
"_id" : ObjectId("5a7a017e0aa5311d9c75c86b"),
"campaignId" : "5a7a017e0aa5311d9c75c86b",
"subCampaigns" : [
{
"_id" : ObjectId("5a7a0eee6849f507d0499a18"),
"name" : "test5",
"campaignId" : ObjectId("5a7a017e0aa5311d9c75c86b"),
"subCampaignId" : "1aKysewspn6CqNGVkv6pyL"
}
{
"name" : "test8",
"amountRaised" : 20.0,
"campaignId" : ObjectId("5a7a017e0aa5311d9c75c86b"),
"subCampaignId" : "5a7a153fe035de396c6f5b3c",
"_id" : ObjectId("5a7a153fe035de396c6f5b3c")
}
],
"name" : "test8",
"__v" : 12,
"totalDonated" : 110.0
}
When I run:
db.getCollection('campaigns').update({"_id": ObjectId("5a7a017e0aa5311d9c75c86b"), "subCampaigns.subCampaignId":"5a7a153fe035de396c6f5b3c"}, {$inc: {"subCampaigns.$.amountRaised": 10}})
In the mongo console it updates the sub document fine. But when I run this in my Mongoose code:
this.campaignModel.update(
{ campaignId: '5a7a017e0aa5311d9c75c86b', 'subCampaigns.subCampaignId': '5a7a153fe035de396c6f5b3c' },
{ $inc: { 'subCampaigns.$.amountRaised': 10}},
(err: any, subResult: any) => {...
The sub document does not have its amountRaised field incremented. From what I can tell they should be identical calls?
If I run an inc at the level higher:
this.campaignModel.findOneAndUpdate(
{campaignId: object.campaignId},
{$inc: {totalDonated: donationAmount}},
() => {...
It works fine, so this must have something to do with the sub document?
I have been playing around with multiple mongoose calls for most of the day but cannot seem to get it to update correctly.

$addToSet in a nested Array item

Considering the following
User collection & sample User document
{
"_id" : ObjectId("575c01f7b8e5999addeb598c"),
"username" : "test.1#gmail.com",
"password" : "<password>",
"firstName" : "Test,
"lastName" : "User"
}
I am trying to run an update request to add an entry in userData.eventData which is meant to be an array
In mongo script I can do
> db.Users.update({_id: ObjectId("575c01f7b8e5999addeb598c")}, {"$addToSet":{"userData.eventData":"My event"}} )
And I have the following result : userData is created as an Object and eventData as a nested Array
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.Users.find({_id: ObjectId("575c01f7b8e5999addeb598c")})
{ "_id" : ObjectId("575c01f7b8e5999addeb598c"), "username" : "test.1#gmail.com", "password" : "<password>", "firstName" : "Test", "lastName" : "User", "userData" : { "eventData" : [ "My event" ] } }
While running the same logic in mongo (using driver version 2.1.21)
// with a properly initialized db object
db.collection("Users").update({"_id" : ObjectId("575c01f7b8e5999addeb598c")}, {"$addToSet": { "userData.eventData": "My Event"}}, function(err, result) {
// do something
});
I receive the following response
result:Object
n:0
nModified:0
ok:1
And indeed the database entry is unchanged.
Is that the way it is meant to behave? I can easily fix this by creating the userData.eventData array but I found disturbing the fact that node's Mongo driver and mongo shell didn't behave the same on this
Thanks in advance for your help & advice
Edit 13/6/16
Mistake was on my side, I missed a 'new' before 'ObjectId(...' in node. With it, it behaves exactly the same as in mongo shell (i.e. 'userData' is created as an Object and it includes 'eventData' array)
No issue, then :)
Update, updates an already existing object in your document.
What you want is insert or use upset which creates a new document when no document matches the query criteria
db.collection.update(
{ name: "Andy" },
{
name: "Andy",
rating: 1,
score: 1
},
{ upsert: true }
);
If you wanted to add an object to your array, you would need $push
// Insert a document in the capped collection
function push (db, collection, search, data, callback) {
db.collection(collection).update(
search, {
$push: data
}, function (err, result) {
console.log("New object pushed");
callback(err);
});
}

Fetch sub-document Mongodb only match with criteria

I have data in mongodb like this:
{
"_id" : ObjectId("55a12bf6ea1956ef37fe4247"),
"tempat_lahir" : "Paris",
"tanggal_lahir" : ISODate("1985-07-10T17:00:00.000Z"),
"gender" : true,
"family" : [
{
"nama" : "Robert Deniro",
"tempat_lahir" : "Bandung",
"tanggal_lahir" : ISODate("2015-07-09T17:00:00.000Z"),
"pekerjaan" : "IRT",
"hubungan" : "XXX",
"tanggungan" : false,
"_id" : ObjectId("55a180f398c9925299cb6e90"),
"meta" : {
"created_at" : ISODate("2015-07-11T20:59:25.242Z"),
"created_ip" : "127.0.0.1",
"modified_at" : ISODate("2015-07-12T15:54:39.682Z"),
"modified_ip" : "127.0.0.1"
}
},
{
"nama" : "Josh Groban",
"tempat_lahir" : "Jakarta",
"tanggal_lahir" : ISODate("2015-06-30T17:00:00.000Z"),
"pekerjaan" : "Balita",
"hubungan" : "Lain-Lain",
"tanggungan" : true,
"_id" : ObjectId("55a29293c65b144716ca65b2"),
"meta" : {
"created_at" : ISODate("2015-07-12T16:15:15.675Z"),
"created_ip" : "127.0.0.1"
}
}
]
}
when i try to find data in sub-document, with this code:
person.findOne({ _id: req.params.person, {'family.nama': new RegExp('robert', 'gi') }}, function(err, data){
// render code here
});
It show all data in Family Data,
Can we fetch or display a data only match with criteria/keyword, for example only "Robert Deniro" row
Thank You
In 'regular' MongoDB, you can use the $ operator for that. I'm not sure if it works with Mongoose, but it's worth a try:
person.findOne({
_id : req.params.person,
'family.nama' : new RegExp('robert', 'gi')
}, {
// Only include the subdocument(s) that matched the query.
'family.$' : 1
}, function(err, data){
// render code here
});
If you need any of the properties from the parent document (tempat_lahir, tanggal_lahir or gender; _id will always be included), you need to add them to the projection object explicitly.
One caveat: the $ operator will only return the first matching document from the array. If you need it to return multiple documents, you can't use this method and (AFAIK) have to postprocess the results after they are returned from the database.
It solved with this code:
var options = {
family: {
$elemMatch: { nama: req.query.keyword }
},
};
person.findOne({ _id: req.params.person, 'family.nama': keyword }, options, function(err, data){
//render code here
});
Thanks to #hassansin & #robertklep

Resources