Avoid push/addToSet null value to mongodb array - mongodb

When using $push or $addToSet operator in mongoose, and the value I give (friend.id) is null or undefined, it will push a null element to the array.
dbUser.findByIdAndUpdate(
_id,
{
$addToSet: {
'friendsBlackList': friendB.id ,
'FriendsWhiteList': friendW.id ,
},
},
{ new: true, upsert: true }
});
How to avoid pushing a null element? Can it be controlled in the mongoose schema? Thank you for your suggestions.

I'm not familiar with Mongoose and its syntax, but what your describing can be done with the following pseudocode:
var update = { $addToSet:{}};
if(friendB.id !=null){
update.$addToSet.friendsBlackList = friendB.id
}
if(friendW.id !=null){
update.$addToSet.friendsWhiteList = friendW.id
}
dbUser.findByIdAndUpdate(_id,update,{ new: true, upsert: true });
Some drivers (ie Morphia) have options you can set to ignore null and empty values. You should check if Mongoose has such options as well.

Related

Find all properties which exists in collection and has not-null or not empty value

I'm trying to find using Robo3T in my collection all properties which have property InternalCode as not null and not empty
db.getCollection('db1.customer').find({ InternalCode : { $exists: true, $ne: null } })
this will return all document which has that property and which are set to not null.
How to deal with scenarios where I want nonempty and not null value?
To get not empty and not null,
db.getCollection('db1.customer').find({ InternalCode : { $exists: true, $nin:[null,""] } })

MongoDB findOneAndUpdate projection

I'm currently using MongoDB and using the findOneAndUpdate method. I'm trying to use the projection however it doesn't seem to be working 100% successfully.
Here is the projection:
{
orderID: '$_id',
_id: false,
user: true,
guild: true,
order: true,
status: true,
orderExpiry: true,
priority: true,
sentAt: true
}
As you can see, I'm trying to set orderID to the value of _id however, it doesn't do anything.
Here is the code I am executing for reference :
await this.db.collection('orders').findOneAndUpdate(filter, { $set: { ...data } },
{ returnOriginal: false, projection: this.getProjectionFields() });
I hope someone can help me, thank you!
As far as I know projection with .find() or similar .findOneAndUpdate() does not support field transformations(adding new field out of existing) which $project in aggregation is capable of doing. So projection can be used just to include or exclude certain fields from result. Although this is true but up-to certain extent this is false, we can transform an array field using projection operators, Check : projection.

MongoDB: Filter on _id == obj._id without setting obj._id to null on insert

I'd like to configure an upsert. If _id already exists on my object, it recognizes that and updates the match. If _id doesn't exist, it should insert the new document and generate an _id. I'd expect { _id: obj._id } to work, but that overrides the auto-generation of _id. The document appears with _id: null. Is there a filter that would work for this? Do I need to route to insert/update in-code?
Edit: add query.
collection.updateOne(
{ _id: entity._id },
{ $set: entity },
{ upsert: true }
)
Edit: try delete.
Even when I delete the property, no luck.
const upsertTest = (collection) => {
const entity = { date: new Date() };
console.log(entity);
// { date: 2019-11-19T22:16:00.914Z }
const _id = entity._id;
delete entity._id;
console.log(entity);
// { date: 2019-11-19T22:16:00.914Z }
collection.updateOne(
{ _id: _id },
{ $set: entity },
{ upsert: true }
);
console.log(entity);
// { date: 2019-11-19T22:16:00.914Z }
}
But the new document is this:
screenshot of new document
You have to use $setOnInsert to Insert _id
let ObjectID = require('mongodb').ObjectID;
collection.updateOne(
{ _id: entity._id },
{ $set: entity,$setOnInsert:{_id:new ObjectID()}},
{ upsert: true }
)
As the name suggests it will set the _id on insert
If you are using mongodb then new ObjectID() should work,
If its mongoose then you can use mongoose.Types.ObjectId() to generate new ObjectID
Well I Found your Issue
Changed in version 3.0: When you execute an update() with upsert: true and the query matches no existing document, MongoDB will refuse to insert a new document if the query specifies conditions on the _id field.
So in a nutshell you cannot insert a new doc using upsert:true if your query is using _id, Reference
First of all, the _id property WILL always exist, whether you set it yourself or let it auto-generate. So there's no need to check if it exists.
The syntax for upsert is as follows:
db.collection.update({
_id: 'the id you want to check for' // can put any valid 'find' query here
}, {
$set: {
foo: 'bar',
biz: 'baz'
}
}, {
upsert: true
});
If a document with the given _id exists, it will be updated with the $set object. If it does not exist, a new one will be created with the properties of the $set object. If _id is not specified in the $set object, a new _id value will be auto-generated, or will keep using the existing _id value.
The key here is using $set, rather than putting the object right in there. Using set will merge and replace the properties. Without $set it will replace the entire document, removing any unset properties.
Edit: Now seeing the actual query you made, I would suggest you delete the _id property from the entity before setting it. This will make sure it is left alone.
const _id = entity._id;
delete entity._id;
// now do your query using the new `_id` value for the ID.
From our comments you mentioned you were using the local database. The local database allows _id to be null. Using any other DB should fix your issue.
If the entity._id is null then it will create a doc with _id null, We can solve this issue by adding Types.ObjectId(). If the _id doesn't exist then it will create a new document with the proper _id. otherwise, it will update the existing document.
const { Types } = require("mongoose")
collection.updateOne({ _id: Types.ObjectId(entity._id) },{ $set: entity },{ upsert: true})

How easy rename keys in mongodb arrays?

I have collection where documents have field as an array. I need to rename one field inside each item of this array, but in mongodb all variants looks very monstrous. I even try to use $[] but I can't refer to old value of object, only custom:
collection.update(
{ customField: { $exists: true } },
{
$set:
{
'payload.oneMoreField.$[].path': 'howReferToOldValue',
},
$unset:
{
'payload.oneMoreField.$[].way': '',
},
},
options
);
Somebody knows an easy way to just change the value of a key in monogodb ?

insering a mongoose record if not found

The mongoose schema looks like:
var followSchema = new Schema({
userId: {type: String, required: true},
following : []
});
The Objective is to look for a user using the ID field and then add items to the following array.
The below method does not work:
var myRecord = FollowModel.findOneAndUpdate({userId: req.user.Id}, {upsert: true});
myRecord.exec(function(err, result) {
result.following.push('Test');
res.status(200).send('New Item Added to Follow List');
});
How is this to be done ?
It does work, you just forgot to include the { "new": true } option, as well as a valid update statment:
FollowModel.findOneAndUpdate(
{ "userId": req.user.Id},
{ "$setOnInsert": {
}},
{ "upsert": true, "new": true },
function(err,result) {
if (err) throw err;
console.log(result);
}
);
The blank $setOnInsert here will no nothing in this case, but otherwise you would put something in there that you wanted created "on insert". This would be applied along with any fields in the "query" portion of the statement.
Other standard update operators can also apply, but generally in the case where something "is" matched that you want to update.
But it's the { "new": true } here that lets the command know to return the "modified or created" document, rather than the "original or non existing" document, which is the default without that option.