Mongoose find query gives results in wrong order - node.js

I am saving an updated array of _id's to an array on a document. If I check the document, everything is updating quite nicely, but when I populate right afterward using a new find query, it doesn't work right. populate wasn't working for me, so I decided to handle it manually and I am successful at filling them in, but they're in the wrong order.
export function sort_update(req, res) {
Action.findOneAndUpdate({
_id: req.query.action
}, {
child_actions: req.body.newArray
}, {
useFindAndModify: false, new: true
}, function(err, doc) {
if (err) return res.send(500, {
error: err
});
console.log("child action id strings after update", doc.child_actions); // ["1", "2"] correct!
Action.find({'_id': {$in: doc.child_actions }}, function(err, child_action_docs) {
if (err) return res.send(500, {
error: err
});
console.log("child action objects after fill", child_action_docs); // [{ _id: "2" }, { _id: "1" }] wrong!
doc.child_actions = child_action_docs;
res.send(doc);
});
});
}
Why are they in the wrong order? Does {'_id': {$in: doc.child_actions }} simply not guarantee any order at all? Do I have to re-sort my objects to the doc.child_actions order deliberately or is there a simpler way of telling mongodb to keep the order in the original array?

Related

Making a double query ( Find inside a Find) in Mongoose

I want to query a document. here's its schema
{
_id,
notes: [{_id: 243234,
text: "hey"},
_id, 421123,
text: "hi"}
]
}
I want to first find the document by _id and then find the value of 'text' on notes[1].
Using this, I can find the actual document but how can I find the object inside notes array? I have to find and update the 'text' inside note.
socket.on("individualnote edit", function(data) {
rooms.find({ _id: data.roomId}, function( err, doc) {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
});
You can use positional $ operator to find and update an element within a sub document array.
The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array.
rooms.findOneAndUpdate({
_id: _id,
'notes.text': 'hey'
}, {
'$set': {
'notes.$.text': 'new text'
}
}).then(() => {
console.log('Success');
}).catch((err) => {
console.log('err', err.stack);
});

Selecting only modified subdocument from Mongo

I have a mongoose query like this:
var query = Events.findOneAndUpdate({ '_id': event._id,'participants._id':participant._id},{'$set': {'participants.$': participant}}, {upsert:false,new: true},function(err,result){
if(err){
return res.status(500).jsonp({
error: 'Unable to update participant'
});
}
console.log(result.participants[0]);
res.jsonp(result.participants[0]);
});
and the query works properly modifying the participants subdocument inside Events collection.
The problem:
I need only the modified participant to be returned as JSON and I am not in need of the entire participants array but I am not able to achieve this since I get all the participants when I do console.log(result.participants);
How do I get only the modified subdocument after the query?
You may have to use the native JS filter() method as in the following:
Events.findOneAndUpdate(
{ '_id': event._id, 'participants._id': participant._id },
{ '$set': { 'participants.$': participant } },
{ upsert: false, new: true },
function(err, result){
if(err){
return res.status(500).jsonp({
error: 'Unable to update participant'
});
}
var modified = result.participants.filter(function(p){
return p._id === participant._id
})[0];
console.log(modified);
res.jsonp(modified);
}
);

Update data in MongoDB with Mongojs using findAndModify()

Yet another first-timer problem here. This gets data from a database and displays it in some text fields (that part is not shown in the code below) and after the user edits it the data should be updated in the database via the findAndModify() method and I think this is where the issue lies. There are no errors, it just doesn't do anything. EDIT The following error is received: MongoError: Either an update or remove=true must be specified
server.js
MongoClient.connect("mongodb://user:secretPassword#aws-us-east-1-portal.7.dblayer.com:10712,aws-us-east-1-portal.10.dblayer.com:10316/database", function(err, db) {
if (err) throw err;
var contactList = db.collection("contactList");
app.put('/contactList/:id', function(req, res) {
var id = req.params.id;
console.log("edited: " + req.body.name); //works up until here
contactList.findAndModify({
query: {_id: mongojs.ObjectId(id)},
update: {$set: {name: req.body.name, email: req.body.email, number: req.body.number}},
new: true
}, function (err, doc) {
res.json(doc);
})
});
controller.js
$scope.update = function() {
$http.put('/contactList/' + $scope.contact._id, $scope.contact).success(function(response) {
refresh();
})
};
If this were me I would first do a couple of things:
Before your call to findAndModify just do a simple find using your query. Make sure you can actually find the object using your query. If that works you know that the 'find' part of the findAndModify is probably ok.
Do some console logging inside the callback handler of the findAndModify call. As it stands you do not do anything if an err is returned from the findAndModify call. It is possible your call is returning an error that you are just ignoring and it may provide some additional insight into your problem.
I would try these two first and see if it helps.
Update:
Example using native:
collection.findAndModify(
{ field: 'some value' },
[],
{ $set: { field2: 'some new value' } },
{ new:true },
function(err, doc) {
//handle err and doc
});

Changing response doc object from findOneAndUpdate

Say I got this lil chunk of code:
Room.findOneAndUpdate({ Roomid: roomid }, { $push: { UsersMeta: UserMeta}}, { new: false }, function (err, room) {
if (err) console.log(err);
console.log('room output:');
console.log(room);
client.emit('others', room);
})
which is searching for one document in db, updates it, and then sends this room doc in pre-updated state back to client. What I need is to make some changes to responded room, particularly remove those _id, __v, and, possibly, any other custom part of doc.
What I was trying to do:
use toObject.transform while creating schema
var RoomSchema = mongoose.Schema({
Roomid: { type: String, unique: true },
///stuff///
});
RoomSchema.options.toObject.transform = function (doc, ret, options) {
// remove the _id of every document before returning the result
delete ret._id;
}
failed: recieved cannot set property 'transform' of undefined error.
Change mentioned chunk of code to:
Room.find({ Roomid: roomid })
.update({ $push: { UsersMeta: UserMeta} })
.select({ _id: 0 })
.exec(function (err, room) {
if (err) console.log(err);
console.log('room output:');
console.log(room);
client.emit('others', room);
})
Failed: always recieve [] in room output.
Now I stopped at manually setting {_id: false} on Schema declaration, completely getting rid of _id in the first place. As I want use custom random id's for rooms, it seems that I don't need those _id anyway. Yet I'm not sure, that such a treatment will not cause some unpleasant consequences.
And, moreover, problem of possible need to leave some non _id doc properties out of response - is an unsolved mystery for me.
Thank you for attention.
you can do the following and it should work;
RoomSchema.set('toJSON', {
transform: function (doc, ret, options) {
delete ret._id;
delete ret.__v;
}
});

Upserting a document with MongoDB, incrementing a field and setting it to 0 if not existent

I'm using MongoDB in node.js
What I would like is to upsert a document in a collection. The document has an unique ID, a lastAccess field, which stores the date of the last time accessed, and a timesAccessed field, which should be set to 0 on document creation and incremented by 1 if updating.
I tried:
// coll is a valid collection
coll.update(
{user: accountInfo.uid},
{user: accountInfo.uid,
lastAccess: new Date(),
$inc: {timesAccessed: 1},
$setOnInsert: {timesAccessed: 0}
},
{upsert: true, w: 1},
function(err, result) {
if (err) throw err;
console.log("Record upserted as " + result);
});
but node says:
MongoError: Modifiers and non-modifiers cannot be mixed
What is a coincise and safe way to do this?
You should either $set the values or update/replace the whole object. So either update(find_query, completely_new_object_without_modifiers, ...) or update(find_query, object_with_modifiers, ...)
Plus, you cannot $set and $setOnInsert with the same field name, so you will start counting from 1 :) Oh, and you don't need to add the find_query items to the update_query, they will be added automatically.
Try:
col1.update( {
user: accountInfo.uid
}, {
$set: {
lastAccess: new Date()
}
$inc: {
timesAccessed: 1
}
}, {
upsert: true,
w: 1
}, function(err, result) {
if(err) {
throw err;
}
console.log("Record upsert as", result);
});

Resources