Mongoose unable to get data from MongoDB database - javascript

I have a model (AccountModel.js) as below and the controller for it. i tried to change one document using postman but i am getting an empty array from the database event though the data is present.
let mongoose = require('mongoose')
let Schema = mongoose.Schema
var ObjectId = Schema.ObjectId
let mySchema = mongoose.Schema({
account_id:ObjectId,
account_key:String,
message:String,
created_at:Date,
updated_at:Date
})
let MySchema = module.exports =
mongoose.model('account',mySchema);
module.exports.get = function(callback,limit){
MySchema.find(callback).limit(limit)
}
and AccountController as below to manage account db. i have consoled the query and the output from the database.
var mongoose = require('mongoose')
var Account = require('../models/AccountModel')
var ObjectId = mongoose.Types.ObjectId;
exports.setMessage = function(req,res){
query = {account_id:new ObjectId(req.body.acnt_id)}
console.log(query,"...")
Account.find(query,function(err,account_data){
if(err){
res.send(err)
}
else{
try{
console.log(account_data,'setWelcomeMessage')
account_data.message =
req.body.welcomeMessage
account_data.updated_at = new Date()
account_data.save((err,data)=>{
if(err){
console.log(err)
res.send(err)
}
res.send({"Status":"Success"})
})
res.send({"Status":"Success"})
}
catch(e){
//console.log(e)
res.send({"Status":"Failed"})
}
}
})
}
below is the database
> db.account.find().pretty()
{
"_id" : ObjectId("5c18fea5c5a6a4ebf7999c0b"),
"account_id" : ObjectId("5c18fbefc5a6a4ebf7999c08"),
"account_key" : "UDS1500",
"message" : "testing message",
"created_at" : ISODate("2018-12-18T14:05:25.637Z"),
"updated_at" : ISODate("2018-12-18T14:05:25.637Z")
}
{
"_id" : ObjectId("5c18feffc5a6a4ebf7999c0c"),
"account_id" : ObjectId("5c18fbaac5a6a4ebf7999c07"),
"account_key" : "UDS1299",
"message" : "testing message2",
"created_at" : ISODate("2018-12-18T14:06:55.968Z"),
"updated_at" : ISODate("2018-12-18T14:06:55.968Z")
}
after calling from POSTMAN i am getting an empty array
Below is the request format
{
"acnt_id":"5c18fbaac5a6a4ebf7999c07",
"welcomeMessage":"test message 3!!"
}
console is as below
{ account_id: 5c18fbaac5a6a4ebf7999c07 } '...'
[] 'setWelcomeMessage'
what might be the problem in getting empty data? i have wasted a lot of time on this.

The culprit is this line
query = {account_id:new ObjectId(req.body.acnt_id)}
where the statement new ObjectId(req.body.acnt_id) creates a new id (regardless of what you pass in the constructor) thus your query fails as there won't be any match in the db. You don't necessarily need to cast the acnt_id string to ObjectId as Mongoose does this for you under the hood, but if need be use
query = {account_id:mongoose.Types.ObjectId(req.body.acnt_id)}
otherwise
query = {account_id:req.body.acnt_id}
will suffice.
A better way to do the update would be to use the findOneAndUpdate method which does an atomic update of your model and mostly used when you want to update a single document in the db and return it to your application, so you can refactor your controller method to:
exports.setMessage = (req, res) => {
const query = { 'account_id': req.body.acnt_id };
const update = {
'$set': {
'message': req.body.welcomeMessage,
'updated_at': new Date(),
}
};
const options = { 'new': true };
Account.findOneAndUpdate(query, update, options, (err, account_data) => {
if (err){
res.send(err)
}
else {
console.log(account_data); // logs the updated account document
res.send({"Status":"Success"})
}
});
}
Also, you can set timestamps in your schema where mongoose assigns createdAt and updatedAt fields to your schema and the type assigned is Date i.e.
let mySchema = mongoose.Schema({
account_id: ObjectId,
account_key: String,
message: String,
}, { timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' } });

.find() returns an array, not a single element. Therefore i'd recommend using the .findOne() method instead.

Thank you for you response. I found answer for my problem.
The reason is that the mongoose has created a model with the plural name. Which means, here i have named the model "account". But here in database it will create/connect to a collection with the name "accounts". I dont know the reason for mongoose not creating/connecting to a collection named "accounts". Since there is no collection named with "accounts" it is always giving me the empty result.
At last, i have changed the collection name to "accounts". Now it working fine.
Please comment the reason, mongoose creating/connecting to plural name of the given model.

//getting from postman .... give the account id in postman
query = {account_id:req.body.acnt_id};
//there is match in DB--- getting the data
Account.find(query,function(err,account_data){
if(err){
res.send(err)
}
u wana update
else{
Accoun.update({account_id:req.body.acnt_id},req.body
};
//on body what you enter in postman that will update and store on DB
IN MY KNOWLEDGE
// just example
Model.update
Updates all documents matching conditions using the update clause. All update values are casted to their appropriate types before being sent.
var conditions = { name: 'bourne' }
, update = { $inc: { visits: 1 }}
, options = { multi: true };
Model.update(conditions, update, options, callback);
function callback (err, numAffected) {
// numAffected is the number of updated documents
})

Related

MongoDB findOne funtion returns null when comparing with id

I am using the following code to get the details of a user when I pass their id as a parameter:
server.get("/users/:id", (req, res) => {
const itemId = req.params.id;
dbCollection.findOne({ _id: itemId }, (error, result) => {
if (error) throw error;
// return item
res.json(result);
});
});
However, this doesn't seem to work, as whenever I run the code, I get returned with a null value.
My question is not the same as many previously asked questions because I have ObjectId('randomId') as my id, and not a string. How can I fix my code?
req.params.id comes as a string while your _id is an ObjectId so this won't work since MongoDB requires type equality first, you need to cast the value:
const itemId = mongoose.Types.ObjectId(req.params.id);
MongoDB wouldn't consider the "itemId" as a MongoDB id, therefore you need to transform it as shown below:
new mongodb.ObjectId(itemId)
This implies that:
const mongodb = require('mongodb')
As others already said, MongoDB expects _id to be an ObjectID. But if you are searching for ONE item, instead of using findOne use findById, which accepts id as a string.
const { Model } = require('./models'); // Model is your Mongoose Schema
server.get("/users/:id", async (req, res) => {
const { id } = req.params;
// This is the same as Model.findOne({ _id: new ObjectId(id) });
const item = await Model.findById(id);
return res.json(item);
});

Sequelize - update query with returning: true succeeds but returns undefined

I have the following function which I use to update the URL to the user's profile pic -
const updateProfilePic = async (req, res) => {
const userId = req.param("id");
if (userId) {
const targetPath = `...`;
User.update(
{
profilePic: targetPath
},
{ where: { id: userId }, returning: true }
)
.then(updatedUser => {
console.log(updatedUser);
res.json(updatedUser);
})
.catch(error => {
console.log(error);
res.status(400).send({ error: error });
});
}
};
This updates the DB successfully - however then obtains [ undefined, 1 ] as the updatedUser instead of the user data - if I remove the returning : true flag, it just returns [ 1 ]. I'm not sure what I'm doing wrong - I'm trying to obtain the user object so that I can pass it on to the client.
I presume you are not using Postgres.
The returning property in options is only supported in Postgres.
Update() returns an array with one or two elements. The first element is the number of affected rows. The second array element is only supported in postgres and will return the updated row.
So you are getting the 1 returned which is the number of rows updated.
Docs

Mongo $addToSet with multiple values correct syntax

I have this mongoose schema:
var listingSchema = new Schema({
street : String,
buildingNumber : Number,
apartmentNumber : Number,
UsersAndQuestions: [{
userID: String,
questionID: [String]
}]
});
And I just want to update it with a new entry to UsersAndQuestions which will consist of a userID which is a String, and a questionID which is also a String (but needs to be inserted into an array).
I am using this PUT request:
app.put('/api/listing/:street/:buildingNumber/:apartmentNumber/addUserInput/:userid/:listingid/:questionid')
So I have all the necessary parameters in hand.
Usually, when I wanted to update a field in a schema I used this code that I wrote:
app.put('/api/listing/:street/:buildingNumber/:apartmentNumber/addReportedUser/:userid/:listingid', function (req, res) {
var listingToUpdate = req.params.listingid;
var idToAdd = req.params.userid;
Listing.update({_id: ObjectId(listingToUpdate)},
{$addToSet: {reportedUsersIDs: ObjectId(idToAdd)}}
, function (err) {
if (err) {
res.send("There was a problem adding the reportedUserID to the listing" + err);
}
else {
console.log("Success adding reportedUserID to listing!");
}
})
});
You can see I used $addToSet and it worked well. But now I want to add two parameters to a field which is an array. I thought about doing something like this:
app.put('/api/listing/:street/:buildingNumber/:apartmentNumber/addUserInput/:userid/:listingid/:questionid', function(req,res){
var listingToUpdate = req.params.listingid;
var idToAdd = req.params.userid;
var questionToAdd = req.params.questionid;
Listing.update({_id: ObjectId(listingToUpdate)},
{$addToSet: {UsersAndQuestions.userID : ObjectId(idToAdd), UsersAndQuestions.questionID : ObjectId(questionToAdd)}}
, function (err) {
if (err) {
res.send("There was a problem adding the user and question to the listing" + err);
}
else{
console.log("Success adding user and question to the listing!");
}
})
});
But I'm obviously getting a SyntaxError.
What is the correct syntax for doing what I tried to do?
Thanks a lot! :)
You need to add object to set UsersAndQuestions:
{$addToSet: {UsersAndQuestions: { userID: idToAdd, questionID: questionToAdd } }}
UPDATE.
I would do it with two queries:
Listing.update({_id: ObjectId(listingToUpdate), 'UsersAndQuestions.userID': idToAdd},
{"$addToSet": {"UsersAndQuestions.$.questionID": questionToAdd}}
, function (err, result) {
if(result.n === 0){
//we haven't found document with the userId - idToAdd
//we need to insert to UsersAndQuestions document with this user
Listing.update({_id: ObjectId(listingToUpdate)},
{$addToSet: {UsersAndQuestions: { userID: idToAdd, questionID: questionToAdd } }},
function(err, res){
})
}
})

How to populate if field is not empty string if empty no need to populate?

I have an app that has huge amount of data previously saved in mongoDB. Now I need to populate some information if referencePeople not empty string. In my app referencePeople is string type instead of mongoose ObjectId type.
I don't want to change my schema. Is there any way to check referencePeople is empty or not before populate. or if empty avoid to populate.
schema:
var OrderSchema = new mongoose.Schema({
customer: {type: mongoose.Schema.Types.ObjectId,ref: 'Customer'},
referencePeople: String, // can be "" or "customer id"
......
});
Tried bellow code but got an exception Cast to ObjectId failed for value "" at path "_id"
exports.getOrders = function(req, res) {
Order.find({})
.populate('customer')
.populate({path: 'referencePeople', model: 'customer'})
.exec(function(error, orders) {
if(error) {
return res.status(400).send({msg: 'Error occurred while getting orders.', error: error});
}
return res.status(200).send(orders);
});
};
Now I want to populate referencePeople if it is not empty string.
Can I check before populate referencePeople is empty or not?
Yes, you need to use match clause of population query
So, your code should be smth like this:
exports.getOrders = function(req, res) {
Order.find({})
.populate('customer')
.populate({
'path': 'referencePeople',
'match': { 'referencePeople': {'$ne': ''} }
})
.exec(function(error, orders) {
if(error) {
return res.status(400).send({msg: 'Error occurred while getting orders.', error: error});
}
return res.status(200).send(orders);
});
};
Mongoose can’t handle multi-level population yet, and populated fields are not Documents. Nesting schemas is helpful but it’s an
incomplete solution. Design your schemas accordingly.
You are trying to reference the 'referencePeople' object using the existing ObjectID in the 2nd populate call
Try this
exports.getOrders = function(req, res) {
Order.find({})
.populate('customer')
.exec(function(error, orders) {
if(error) {
return res.status(400).send({msg: 'Error occurred while getting orders.', error: error});
}
//Try changing the referencePeople here
return res.status(200).send(orders);
});
};
REFERENCE: MongoDB

Assign property value doesn't work in Mongoose

My query is:
db.Room.find({}, function (err, rooms) {
if (!err) {
async.each(rooms, function (room, done) {
db.User.find({}, function (err, users) {
if (err) {
done(err)
} else {
room.users = users
room._name = room.name
done()
}
})
}, function (err) {
if (!err) {
socket.emit('read:rooms', rooms)
}
})
}
})
and schemas are:
room:
var mongoose = require('mongoose')
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Room = new Schema({
name: String
});
module.exports = Room
user:
var mongoose = require('mongoose')
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var User = new Schema({
email: String
});
module.exports = User
but in front-end:
socket.on('read:rooms', function (rooms) {
$scope.rooms = rooms
})
but rooms has no users property, help me, please
It's because the Rooms schema doesn't have a users property.
So, there are a few ways to fix it. Since it looks like though you want the users property to be something that really isn't part of the schema, and is a client-side join rather than work that is done on the database (which is a good!), I'd suggest you convert the data to be just plain old JavaScript objects when you send it over the socket (this would have happened anyway, you're just doing it a bit earlier).
So, when the find returns, it is actually returning a fully-realized MongooseJS model object. While you can set dynamic properties on the object instance, they aren't part of the "data" of the model, so that when it is serialized later to the client, only the properties that are documented will be available.
So, here is an example of what I'd suggest:
db.Room.find({}, function (err, rooms) {
if (!err) {
var oRooms = [];
async.each(rooms, function (room, done) {
/* etc. your code */
} else {
var oRoom = room.toObject();
oRoom.users = users
oRoom._name = room.name
oRooms.push(oRoom);
done()
}
This technique would use the toObject functionality of a Model to return a JavaScript object (not a Mongoose model). That way, you can do what you'd like to the object, including adding new properties dynamically.
Later, of course, make sure you send the new array of rooms to the client:
if (!err) {
socket.emit('read:rooms', oRooms)
}

Categories