mongoDB: remove empty objects in an object-array - javascript

Unfortunately I got some false objects in an array in some documents, which are structured like this:
{
"_id" : "8vJY4baMbdYkgHian",
"title" : "Cars",
"tradename" : [
{
},
{
"element" : "Audi"
},
{
"element" : "Mercedes"
}
]
}
As you can see in this example, the first object in the array is empty. How can I remove empty objects in all tradename-arrays of all documents in the collection?
Collection.update(
{ 'tradename': {} },
{ $pull: { 'tradename.$': '' } }
);

An alternative approach to remove empty objects from an array with no assumptions:
db.a.update(
{"tradename": {}},
{ $pull: { 'tradename': {$in:[{}]} } },
{ "multi": true }
);

The following update operation using $pull updates all documents in the collection to remove empty objects from the array tradename, given that the embedded document has the element property only:
db.collection.update(
{ },
{ "$pull": { "tradename": { "element": { "$exists": false } } } },
{ "multi": true }
)

Related

How to get array length instead of full array in find()?

I have a mongodb (using mongoose) collection ("items") which includes an array ("images") among its properties. Some example documents:
[
{
"_id" : ObjectId("543fa67e9672ec37ebe3d026"),
"name" : "Alice",
"images" : [
{ url: "http://images.com/1.jpg" },
{ url: "http://images.com/2.jpg" },
{ url: "http://images.com/3.jpg" },
]
},
{
"_id" : ObjectId("543fa67e9672ec37ebe3d027"),
"name" : "Bob",
"images" : [
{ url: "http://images.com/4.jpg" },
{ url: "http://images.com/5.jpg" },
]
},
]
I want to implement a query which returns - along with other document properties - the array length (and not the array contents). I know I can get the array length with
db.items.aggregate([
{ "$project" : { "_id" : 0, "imagesLength" : { "$size" : "$images" } } }
])
But I need the imagesLength values along with the documents returned with a find:
db.items.findMany(
{ ...filter },
{ name: 1, imagesCount: 1 }
);
The question is: how can I get the array length along with the find results ?
You can do same as aggregation projection in find's second argument,
Starting in MongoDB 4.4, as part of making find projection consistent with aggregation’s $project stage,
db.items.find(
{ ...filter },
{
_id: 0,
name: 1,
images: { $size: "$images" }
})
Playground
You can add a match stage at first in your aggregation to filter the results. Then you can project all fields needed and generate the new ones.
db.items.aggregate([
{ "$match" : { ...filter },
{ "$project" : { "imagesLength" : { "$size" : "$images" }, "name": 1 } }
])

Mongoose: insert object into a sub-document array

I am trying to insert a time object into the times array for a specific activity name for a specific user. For example, if the user was "someuser" and I wanted to add a time to the times for guitar I am unsure as to what to do.
{
username: "someuser",
activities: [
{
name: "guitar",
times: []
},
{
name: "code",
times: []
}
]
}, {
username: "anotheruser",
activities: []
}
This is currently the function that I have, I cannot figure out what I am doing wrong, any help would be greatly appreciated:
function appendActivityTime(user, activityName, newRange) {
User.updateOne(
{username: user, 'activities.name': activityName},
{ $push: {'activities.$.times': {newRange}},
function (err) {
if (err) {
console.log(err);
} else {
console.log("Successfully added time range: " + newRange);
}
}}
);
}
appendActivityTime("someuser", "guitar", rangeObject);
i've tried your attempt and it worked for me:
db.getCollection("test").updateOne(
{ username: "someuser", "activities.name": "guitar" },
{ $push: { "activities.$.times": { from: ISODate(), to: ISODate() } } } //Don't worry about ISODate() in node.js use date objects
)
results:
{
"_id" : ObjectId("5f6c384af49dcd4019982b2c"),
"username" : "someuser",
"activities" : [
{
"name" : "guitar",
"times" : [
{
"from" : ISODate("2020-09-24T06:15:03.578+0000"),
"to" : ISODate("2020-09-24T06:15:03.578+0000")
}
]
},
{
"name" : "code",
"times" : [
]
}
]
}
what i would suggest you using instead is arrayFilter, they are much more precise and when you get used to them, they became very handy
If you are not confident with updating nested documents, let mongoose make the query.
let document = await Model.findOne ({ });
document.activities = new_object;
await document.save();

How to pull an object from array in MongoDB

I have pull friend request when it is accepted or canceled. So, when I try to pull it from array, it doesn't work.
It matches for 1 document but 0 document modified.
When I delete the requested_at field from user field, it works well.
Where do I make mistake at ?
MongoDB Document
{
"_id" : ObjectId("5cb18680aa024b2d441f93cc"),
"friends" : [],
"friend_requests" : [
{
"user" : {
"id" : ObjectId("5cb14fd7db537905c89e0a72"),
"requested_at" : ISODate("2019-04-14T17:51:00.588Z")
}
}
]
}
MongoDB Query
db.getCollection('users').updateOne(
{ _id: ObjectId("5cb18680aa024b2d441f93cc") },
{
$pull: {
friend_requests: {
user: {
id: ObjectId("5cb14fd7db537905c89e0a72")
}
}
}
});
Result
{
"acknowledged" : true,
"matchedCount" : 1.0,
"modifiedCount" : 0.0
}
Use dot notation to specify a condition:
db.users.updateOne(
{ _id: ObjectId("5cb18680aa024b2d441f93cc") },
{
$pull: {
"friend_requests": {
"user.id": ObjectId("5cb14fd7db537905c89e0a72")
}
}
});

Nodejs with Mongoose returns one object value instead of multiple in an array

data=[{
locId: '332wn',
locadetails: [
{ loc: 'ny',
status: true
},
{ loc: 'ca',
status: null
},
{ loc: 'tx',
status: null
}
]
}]
I have following query that is trying to find all the locdetails that have open value as null or false
Loc.find({'locId': id}, {'locadetails' : {$elemMatch: {'status': {$ne: true}}}}, (err, locs)=>{
if(err) {
retrun callback(err);
}
callback(null, locs)
});
Problem I have is this query will only return one value o locadetails with null while it should return two as seen in the data.
Please let me know what to do so I can get whole array of items that have status field as null or false ...Thanks
$elemMatch will return first matching element from an array based on a condition. Use Aggregation instead.
Both the $ operator and the $elemMatch operator project the first
matching element from an array based on a condition. Reference
Loc.aggregate([
{ $match: { "locId": "332wn" } },
{ $unwind: "$locadetails" },
{ $match: { "locadetails.status": { $ne: true } } },
{ $group: { _id: "$_id", locId: { $first: "$locId" }, locadetails: { $push: "$locadetails" }, } }
])

How to remove element in mongodb array

How can I remove just one element of an array in a collection like this:
{
"_id" : "Y9BBFa4c4vMiAkjbi",
"metadata" : {
"tags" : [
"Anything",
"Something",
"More"
]
}
}
In this example I just want to remove 'Something' - if it is existing.
var tag = 'Something';
if (Collection.find({ 'metadata.tags': tag }).count()) {
Collection.update(
{ _id: id },
{ $pull: { 'metadata.tags': tag } }
);
}
Just make sure your $pulltargets the array element you want to remove:
Collection.update({ _id: id },
{ $pull: { 'metadata.tags': { $eq: "Something" }}}
);

Categories