I try to query MongoDB inside nodejs to get data for _id x I use
async function getTestData(id){
return new Promise((resolve, reject) => {
MongoClient.connect(uri, { useNewUrlParser: true, keepAlive: 1 }, function(err, client) {
const dbo = client.db("test");
var query = { _id: id };
dbo
.collection("smscripts")
.find(query)
.project({ 'data' : 1})
.toArray(function(err, items) {
err
? reject(err)
: resolve(items);
});
});
});
}
Query is
{ _id: '5dada7dfdca94dbaf65d9547' }
But I always get back an empty array. Anybody can help me out why the array is always empty? By the way, err is null. The id definitely exists.
in mongo db _id are prefix with ObjectId
so you need value first try this
id = ObjectId("507c7f79bcf86cd7994f6c0e")
and then compare it to ID.
hope it helps
First You need to import..
import { ObjectId } from "bson"
Then in Your code " var query = { _id: id }; " replace it with this..
var query = { '_id' : ObjectId(id) }
Then, in your code you are using .toArray() method. this would takes more time to
convert result to array. so you need to use await keyword before moving on.
Using Async-Await pattern this is very simple ..
const client = await MongoClient.connect(uri, { useNewUrlParser: true, keepAlive: 1 })
.catch(err => { console.log(err); });
if (!client) return;
try {
const dbo = client.db('test');
let collection = dbo.collection('smscripts');
let query = { '_id' : ObjectId(id) };
let projection = { 'data' : 1 } ;
let cursor = await collection.find(query, projection).toArray();
console.log(cursor);
return cursor;
} catch (err) {
console.log(err);
} finally {
client.close();
}
hope this works for you.
Related
So I am trying to find all documents in a database between 'X' and 'X' dates and then order those by userID. This is what I have so far:
await Expense.find(
{'date' :{'$gte': new Date(startDate), '$lte': new Date(endDate)}}),{sort: {_id: 1}}.exec(function(err, data){
if(err){
console.log('Error Fetching Model');
console.log(err);
}
console.log(JSON.stringify(data, null));
expenseArray = data;
console.log(expenseArray);
But it keeps giving me "TypeError: {(intermediate value)}.exec is not a function"
For added clarification I am trying to write this in mongoose:
"SELECT employeeName, SUM(amount)
FROM reimbursements
WHERE d8 BETWEEN '$startDate' AND '$endDate'
GROUP BY employeeName
ORDER BY employeeName;";
What am I doing wrong? Thank you in advance :D
Your query has few syntax issues, Please try this :
Update :
Below old code will work, but it would be better if you try this way :
try {
let data = await Expense.find(
{ 'date': { '$gte': new Date(startDate), '$lte': new Date(endDate) } }).sort({ _id: 1 })
/** .find() will not return null, it will either return [] or [with matched docs] */
if (data.length) { // checks data != []
console.log(data)
} else { // data == []
console.log('Empty - no docs found')
}
} catch (error) {
console.log('Error Fetching Model');
console.log(error);
}
Old :
await Expense.find(
{ 'date': { '$gte': new Date(startDate), '$lte': new Date(endDate) } }).sort({ _id: 1 }).exec(function (err, data) {
/** sort is not an option for .find() not like aggregate, it has to be on cursor which is result of .find() & .exec() should be at end which is either .find() or .sort() */
if (err) {
console.log('Error Fetching Model');
console.log(err);
}
console.log(JSON.stringify(data, null));
expenseArray = data;
console.log(expenseArray)
})
Sample : mongooseModel.find().sort().exec()
Ref : cursor.sort
I am trying to update a document with nested subdocuments, but i always retrieve the previus document.
i tried
{ returnOriginal: false }
but it is not working...
this is my code in nodejs
almacenCtrl.updateAlmacen = async (req, res) => {
almacen = await almacenModel.findOneAndUpdate(req.params.id, { $set: req.body }, { returnOriginal: false }, function (err, updated) {
res.json(updated)
})
}
what am i doing wrong?
//After update i check with mongoshell and the update was updated successfully
Use {new : true} as given below:
almacenCtrl.updateAlmacen = async (req, res) => {
almacen = await almacenModel.findOneAndUpdate(req.params.id, { $set: req.body }, { new: true }, function (err, updated) {
res.json(updated)
})
}
I have a PUT route to update value. I am hitting this route from two places. One is sending information about details and one about completed. The problem is that mongoose is updating booth even though it gets value from only one.
So if I send information about completed that it is true and latter I hit this route with new details (that dont have completed value) it will update completed also to false. How do I update just the value that was changed?
router.put('/:id', (req, res) => {
Todo.findOne({_id:req.body.id}, (err, foundObject) => {
foundObject.details = req.body.details
foundObject.completed = req.body.completed
foundObject.save((e, updatedTodo) => {
if(err) {
res.status(400).send(e)
} else {
res.send(updatedTodo)
}
})
})
})
EDIT:
Thanks to Jackson hint I was managed to do it like this.
router.put('/:id', (req, res) => {
Todo.findOne({_id:req.body.id}, (err, foundObject) => {
if(req.body.details !== undefined) {
foundObject.details = req.body.details
}
if(req.body.completed !== undefined) {
foundObject.completed = req.body.completed
}
foundObject.save((e, updatedTodo) => {
if(err) {
res.status(400).send(e)
} else {
res.send(updatedTodo)
}
})
})
})
const updateQuery = {};
if (req.body.details) {
updateQuery.details = req.body.details
}
if (req.body.completed) {
updateQuery.completed = req.body.completed
}
//or
Todo.findOneAndUpdate({id: req.body.id}, updateQuery, {new: true}, (err, res) => {
if (err) {
} else {
}
})
//or
Todo.findOneAndUpdate({id: req.body.id}, {$set: updateQuery}, {new: true}, (err, res) => {
if (err) {
} else {
}
})
Had a function similar to this my approach was this
const _ = require('lodash');
router.put('/update/:id',(req,res, next)=>{
todo.findById({
_id: req.params.id
}).then(user => {
const obj = {
new: true
}
user = _.extend(user, obj);
user.save((error, result) => {
if (error) {
console.log("Status not Changed")
} else {
res.redirect('/')
}
})
}).catch(error => {
res.status(500);
})
};
Taking new : true as the value you updating
It gets kinda ugly as the fields to be updated get increased. Say 100 fields.
I would suggest using the following approach:
try {
const schemaProperties = Object.keys(Todo.schema.paths)
const requestKeys = Object.keys(req.body)
const requestValues = Object.values(req.body)
const updateQuery = {}
// constructing dynamic query
for (let i = 0; i < requestKeys.length; i++) {
// Only update valid fields according to Todo Schema
if ( schemaProperties.includes(requestKeys[i]) ){
updateQuery[requestKeys[i]] = requestValues[i]
}
}
const updatedObject = await TOdo.updateOne(
{ _id:req.params.idd},
{ $set: updateQuery }
);
res.json(updatedObject)
} catch (error) {
res.status(400).send({ message: error });
}
I am trying to populate my array of an object id's how can i do ??
Function
$scope.assignEmployees = function () {
var chkArray = [];
var companyName = $scope.selectedComapny.companyName;
var Indata = {chkvalue:chkArray,company_name:companyName};
$("#employee_name:checked").each(function() {
chkArray.push($(this).val());
});
$http({
method : 'PUT',
url : '/api/projects',
data : Indata
})
.success(function (data){
console.log(data);
});}
Mongoose api
Population code:-
Project.findOne({client : company_name})
.populate('assignedTo')
.exec(function(err, project) {
if (err) return;
while(i<employee_id.length){
project.assignedTo.push(employee_id[i]);
project.save(function(err) {
if (err) return;
})
i++;
}
});
This code is work but it insert value 4 times any idea guys.
You can use this code to push all elements of Array to an Array in mongoose.
Project.update(
{ client: company_name },
{ "$pushAll": { "assignedTo": employee_id } },
function (err, raw) {
if (err) return handleError(err);
console.log('The raw response from Mongo was ', raw);
}
);
I've looked through the mongoose API, and many questions on SO and on the google group, and still can't figure out updating embedded documents.
I'm trying to update this particular userListings object with the contents of args.
for (var i = 0; i < req.user.userListings.length; i++) {
if (req.user.userListings[i].listingId == req.params.listingId) {
User.update({
_id: req.user._id,
'userListings._id': req.user.userListings[i]._id
}, {
'userListings.isRead': args.isRead,
'userListings.isFavorite': args.isFavorite,
'userListings.isArchived': args.isArchived
}, function(err, user) {
res.send(user);
});
}
}
Here are the schemas:
var userListingSchema = new mongoose.Schema({
listingId: ObjectId,
isRead: {
type: Boolean,
default: true
},
isFavorite: {
type: Boolean,
default: false
},
isArchived: {
type: Boolean,
default: false
}
});
var userSchema = new mongoose.Schema({
userListings: [userListingSchema]
});
This find also doesn't work, which is probably the first issue:
User.find({
'_id': req.user._id,
'userListings._id': req.user.userListings[i]._id
}, function(err, user) {
console.log(err ? err : user);
});
which returns:
{ stack: [Getter/Setter],
arguments: [ 'path', undefined ],
type: 'non_object_property_call',
message: [Getter/Setter] }
That should be the equivalent of this mongo client call:
db.users.find({'userListings._id': ObjectId("4e44850101fde3a3f3000002"), _id: ObjectId("4e4483912bb87f8ef2000212")})
Running:
mongoose v1.8.1
mongoose-auth v0.0.11
node v0.4.10
when you already have the user, you can just do something like this:
var listing = req.user.userListings.id(req.params.listingId);
listing.isRead = args.isRead;
listing.isFavorite = args.isFavorite;
listing.isArchived = args.isArchived;
req.user.save(function (err) {
// ...
});
as found here: http://mongoosejs.com/docs/subdocs.html
Finding a sub-document
Each document has an _id. DocumentArrays have a special id method for looking up a document by its _id.
var doc = parent.children.id(id);
* * warning * *
as #zach pointed out, you have to declare the sub-document's schema before the actual document 's schema to be able to use the id() method.
Is this just a mismatch on variables names?
You have user.userListings[i].listingId in the for loop but user.userListings[i]._id in the find.
Are you looking for listingId or _id?
You have to save the parent object, and markModified the nested document.
That´s the way we do it
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Profile.findById(req.params.id, function (err, profile) {
if (err) { return handleError(res, err); }
if(!profile) { return res.send(404); }
var updated = _.merge(profile, req.body);
updated.markModified('NestedObj');
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(200, profile);
});
});
};