Reputation: 14404
I have tried dozens of solutions, and none of these worked and most of them are deprecated.
I have a collection with documents like this:
_id: 5d99ef3285c93711828cd15d
code: 1234
name: "Foo"
surname: "Bar"
address: "That street"
phone: 1234567
I would like to insert new document only if there isn't any document with the same code
.
My last try was this:
const result = await db.collection('users').findOneAndUpdate(
{ code: user.code },
{
$setOnInsert: user,
},
{
upsert: true,
}
);
but I get E11000 duplicate key error collection...
updateOne()
returns the same error; update()
is deprecated...
So, how to add only new document and get the result (true if document has been added or false if it already exists)?
Thank you.
Upvotes: 0
Views: 214
Reputation: 2274
As far as my knowledge is,
with $set and $setOnInsert, we can not update/insert the same field.
i.e. $set and $setOnInsert should be mutually exclusive.
It works if the document is being updated, but throws an exception if document is being inserted.
In case of update, $setOnInsert will be ignored.
In case of insertion, both will be executed.
I think the solution would be,
use returnNewDocument and have one field in the schema isUpdated
defaults to false.
Note:
make sure whenever you use "insert" operation on the collection, you don't add
isUpdated
which will be set to false then or set it to false.
form a query like
db.collection('users').findOneAndUpdate(
{ code: user.code },
{
$set: user, // which has user.isUpdated set to true
},
{
upsert: true,
returnNewDocument: false, // (by default it is false only)
}
);
With this logic,
So let's go step by step,
If the document doc1
is not present, it will be inserted, and mongo will return the response null
. You will know, it is Inserted.
If the document doc2 is present(considering this logic is not applied on the previously inserted document doc2
before and isUpdated
field is not present in doc2), it will execute $set so in returned cursor, this field not present i.e. undefined
, so you know from this, it is updated.
let's say we fire the same query for doc1
again (which is present and we have applied our new logic), then there are two cases
a. it will be updated and in the cursor, we have isUpdated
equal to false.
b. it will be updated and in the cursor, we have isUpdated
equal to true.
In both case you know it is Updated
I think this approach should solve your problem.
Please share if this helps you, or you find any other solution.
UPDATE
ACTUALLY
You dont even need another field isUpdated
, without this fiels this should work with the same logic.
i.e. If cursor is null then its inserted, if not null then its updated.
Upvotes: 1
Reputation: 5600
Try this one
db.collection("users").findOne({ code: user.code }, (err, data) => {
if (data) {
return res.send(false);
} else {
// a document
var user = new User({
code: code,
name: "Foo",
surname: "Bar",
address: "That street",
phone: 1234568
});
// save model to database
user.save(function(err, book) {
if (err) return console.error(err);
return res.send(true);
});
}
});
Upvotes: 0
Reputation: 44
Users.findOneAndUpdate({code:user.code}, {upsert: true, new: true, setDefaultsOnInsert: true }, function(error, result) { if (error) return; // do something with the document }).
I think it would work. Let us know if you have any questions.
Upvotes: -1
Reputation: 582
You could use findOne to see if a user with that code exists first
const result = await db.collection('users')
.findOne({ code: user.code });
if( result ){
return res
.status(400)
.json({ errors: [{ msg: 'User already exists' }] });
}
//create
user = new User({
code = code,
name = name,
foo = foo
)}
//save
user.save();
res.json(user);
Upvotes: 0
Reputation: 106
You can simply wrap the request with a try/catch block to catch the Error. Then return false when this exception occured.
Upvotes: 0
Reputation: 38
You can still run a query like this;
document = db.collection('users').findOne({code:userCode});
if(document == null){
//document doesn't exists so you can use insertOne
}
else{
// document exists, sou you can update
}
it won't be efficient but it'll do the work.
Upvotes: 0