findOneAndUpdate with Upsert always inserting a new user - node.js

I want to do is update a record and insert it if it doesn't exist with mongoose. Here is my code:
module.exports.upsertUser = function(user) {
var options = {userName : 'Ricardo'}
Users.findOneAndUpdate({email: user.email}, options, {upsert:true}).exec();
}
And:
var promise = Users.upsertUser(user);
promise
.then(function(results){
...
}
.catch(function(err){
...
}
When I execute the promise, each time a new user is created with the same email.
I'm not sure if I'm performing the update incorrectly. I've tried it in the same way but with update and it does not work either.
Can you help me? Thanks!

You need to put the return without the exec:
module.exports.upsertUser = function(user) {
var options = {userName : 'Ricardo'}
return Users.findOneAndUpdate({email: user.email}, options, {upsert:true, new: true});
}
var promise = Users.upsertUser(user);
promise.then(function(results){
if(results) {
console.log(results);
} else {
console.log('!results');
}
}.catch(function(err){
...
}
FYI:
The default is to return the unaltered document. If you want the new, updated document to be returned you have to pass an additional argument: {new:true} with the upsert option.

according to your coding what findOneAndUpdate() does is that it finds this document/user's document that you are looking for to edit which in this case what you are using to search for this user's document that you want to edit it's document is with his email. Now your second argument modifies that part of the document that you wanted to modify, but this option has to be attached with some mongodb operators (pay a visit to this link for a list of them: https://docs.mongodb.com/manual/reference/operator/update/) but in your case what you need is the $set operator.so i would modify your code like this:
module.exports.upsertUser = function(user) {
var options =
Users.findOneAndUpdate({email: user.email}, {$set:{
userName : 'Ricardo'
}}, {
returnOriginal: true}).exec();
};
so try the above modification let's see how it works

Related

Unown Way To Change Parameter Inside Mongoose

I am having some issues with saving an object parameter into a mongoose map. My collection looks like this. The collection's name is guildtickets:
{
"_id":"813915771067301888",
"maxopenTickets":"5",
"serverticketnum":"2",
"opentickets": {
"850608478229626891": {
"ticketname":"ticket-0001",
"ticketstatus":"open",
"ticketcreatedby":"843644509324705814"
}
},
"__v":0}
I wish to change the ticketstatus parameter to closed, so the result should be "ticketstatus": "closed". So far I am using:
var queryTicketSchema = await GuildTicketsSchema.findOne({
_id: message.guild.id
});
queryTicketSchema.get(`opentickets`).get(`${message.channel.id}`).ticketstatus = 'closed';
The issue with the code above, is that when logging the collection, the ticketstatus parameter is showed as closed, but while in MongoDB compass, the parameter is still listed as open. Any help is appreciated and more than welcome! Tysm!
Try this:
let ticket = await GuildTicketsSchema.findOne({
_id: message.guild.id
});
ticket.get(`opentickets`).get(`${message.channel.id}`).ticketstatus = 'closed';
await GuildTicketsSchema.findByIdAndUpdate(ticket._id, ticket);

Proper way to check a property of Mongoose Document is empty

Suppose a schema
const sch = new mongoose.Schema({
obj: {
subObj: String;
}
});
Then I observe that an non-existing or empty property of a document gives me isEmpty == false.
import { isEmpty } from 'lodash';
// Insert an empty document (i.e. no `obj` property)
Sch.create([{}]);
Sch.findOne({}. (err, doc) => {
// Below gives `{}`
console.log(doc.obj);
// Below gives `false`
console.log(`isEmpty == ${isEmpty(doc.obj)`);
});
I suspect that it is because the document contains obj as its key, i.e. Object.keys(doc).includes('obj') == true or Object.getOwnPropertyNames(doc).includes('obj') == true. But I have no idea to deal with it.
What is a proper way to check emptiness of a mongoose document property ?
Update:
The reason that you are getting that is:
console.log(Object.keys(doc.obj), Object.keys({}));
when running the command above I get: [ '$init', 'subObj' ] [] which means that your Object is not really empty, lodash is probably checking those attributes
You could use something like this:
Sch.findOne({}, (err, doc) => {
if (JSON.stringify(doc.obj) === JSON.stringify({}) ) {
// logic goes here
}
});
I found the solution in mongoose itself. The below does what I tried with lodash
doc.$isEmpty('obj')
Reference
Document.prototype.$isEmpty()

Mongoose get updated document after instance.update()

I am executing a mongoose Model.findById() function in order to return a single instance by utilizing an express route.
Model.findById(modelid)
.then(instance => {
if(instance.isOwnedBy(user)) {
return instance.update({$push: {days: req.params.dayid}}, {new: true})
.then(foo => res.send(foo))
} else {
res.status(401).send("Unauthorized")
}
})
the above code returns an object containing the opTime, electionId...etc instead of returning the newly updated document instance. How am I able return the newly updated document after the instance.update() method?
If instance.isOwnedBy(user) and _id: modelid can be merged into one mongo query, it's better to use findOneAndUpdate() but in that way, if it doesn't find any document match, you can not know which part of the query causes the not found.
And because I don't know much about your models, conditions, I can not answer how to do it with findOneAndUpdate() but there is another way that modify the document and call save() method.
Example base on your code:
Model.findById(modelid)
.then(instance => {
if(instance && instance.isOwnedBy(user)) {
if(instance.days) instance.days.push(req.params.dayid);
else instance.days = [req.params.dayid];
instance.save().then(function(instance){
res.send(instance);
})
} else {
res.status(401).send("Unauthorized")
}
})
Note: You should check if the instance exist or not before modify it.

Mongoose doesn't update my fields

I'm trying to update an entries, if they are found in my Mongo DB:
exports.insert = function(project, data) {
data.forEach(function(d){
d.project = project;
var asset = new Asset(d);
Asset.findOne({
project: asset.project,
ip: asset.ip
}, function(err, match) {
if (err) { return next(err); }
if (match) {
console.log('asset found, updating');
match.mac = 'blablah';
match.save();
}
});
});
};
I also tried to update like this:
asset.mac = 'blalah';
match.update(asset);
In both cases my fields don't update in the DB. I see no change.
There may be smarter ways to do this but I need to be able to use save or update to do it for future.
NB: Although findOneAndUpdate may be the preferred way of doing this, I'm really curious to know why save() or update() do not work in my case. I would like to know how to use those methods to update my document.
If you're trying to find one entry and update it, you should use findOneAndUpdate:
Asset.findOneAndUpdate({
project: asset.project,
ip: asset.ip
}, {
mac: 'blablah'
}, function (err, docThatWasUpdated) {
....
})

node.js strange syntax for "delete"

what's the delete used for? I didn't see such grammar before, can anybody help me?
the code snippet is very easy and it is used the node.js , mongoose , mongodb
function _update(game, callback) {
if (!game) {
callback(new Error("Game must be provided."));
return;
}
if (!game.gameId) {
callback(new Error("Game id should be provided"));
return;
}
var updates = (game instanceof Game) ? game.toObject() : game;
delete updates._id;
updates.modifiedDate = new Date();
Game.findOneAndUpdate({"_id": game.id, "deleted" : {"$ne": true}}, updates, callback);
}
delete in JavaScript removes the property from the object.
var game = {
id: 1
}
console.log(game); // Object {id: 1}
delete game.id
console.log(game); // undefined
It is used to remove a property from an object. So in this instance it removes the _id property from updates

Resources