Delete objects that met a condition inside an array in mongodb - mongodb

My collection has array "name" with objects inside. I need to remove only those objects inside array where "name.x" is blank.
"name": [
{
"name.x": [
{
"_id": "607e7fcca57aa56e2a06b57b",
"name": "abc",
"type": "123"
}
],
"_id": {
"$oid": "62232cd70ce38c5007de31e6"
},
"qty": "1.0",
"Unit": "pound,lbs"
},
{
"name.x": [
{
"_id": "607e7fcca57aa56e2a06b430",
"name": "xyz",
"type": "123"
}
],
"_id": {
"$oid": "62232cd70ce38c5007de31e7"
},
"qty": "1.0",
"Unit": "pound,lbs"
},{
"name.x": []
,
"_id": {
"$oid": "62232cd70ce38c5007de31e7"
},
"qty": "1.0",
"Unit": "pound,lbs"
}
I tried to get all the ids where name.x is blank using python and used $pull to remove objects base on those ids.But the complete array got deleted.How can I remove the objects that meet the condition.

Think MongoDB update with aggregation pipeline meets your requirement especially to deal with the field name with ..
$set - Update the name array field by $filter name.x field is not an empty array.
db.collection.update({},
[
{
$set: {
name: {
$filter: {
input: "$name",
cond: {
$ne: [
{
$getField: {
field: "name.x",
input: "$$this"
}
},
[]
]
}
}
}
}
}
],
{
multi: true
})
Sample Mongo Playground

Related

How to use an existing field value with $push in MongoDb?

I have the following Mongo collection
{
"_id": ObjectId("5524d12d2702a21830bdb8e5"),
"code": "Apple",
"name": "iPhone",
"parameters": [
{
"code": "xxx",
"name": "Andrew",
"value": "9",
},
{
"code": "yyy",
"name": "Joy",
"value": "7",
},
]
}
I am using the following query to push into the parameters array object
db.coll.update({
"parameters.name": "Andrew"
},
{
$push: {
"parameters": {
"code": "$code",
"name": "bar",
"value": "10",
}
}
},
{
multi: true
})
However, for the value of code, I want to use the value of the object that matched (i.e. the object with parameters.name == "Andrew", which here is xxx.
Here's a playground link to the problem https://mongoplayground.net/p/v-j1tCCjiWq
Also, I am using a really old version (3.2) of MongoDb. It would be preferable if the solution worked with that.
With MongoDB v4.4+, you can first $match with your criteria. Chain up $first with $filter to extract the array element you want. Use $concatArrays to append a new element(i.e. same as $push) to the array and $merge to update back into the collection.
db.coll.aggregate([
{
$match: {
"parameters.name": "Andrew"
}
},
{
$set: {
parameters: {
"$concatArrays": [
"$parameters",
[
{
"$mergeObjects": [
// get the object matched
{
"$first": {
"$filter": {
"input": "$parameters",
"as": "p",
"cond": {
$eq: [
"Andrew",
"$$p.name"
]
}
}
}
},
// update the object matched with other fields with constant value
{
"name": "bar",
"value": "10"
}
]
}
]
]
}
}
},
{
"$merge": {
"into": "coll1",
"on": "_id"
}
}
])
Mongo Playground

Get Array containing objects to normal object which have value as key in MongoDb result

I have this in
[
{
"date": "2022-12-03T12:16:52.403Z",
"configs": [
{
"name": "Shubham",
"values": [
{
"text": "172cm",
"type": "Height",
},
{
"text": "80kg",
"type": "Weight",
},
{
"text": "male",
"type": "Gender",
},
],
}
]
},
{....},{....}
]
Want to convert config into objects like this
[
{
"date": "2022-12-03T12:16:52.403Z",
"configs": {
"name": "Shubham",
"Height": "172cm",
"Weight": "80kg",
"Gender": "male",
}
},
{...},{...},
]
I know how to do in Javascript array map method but need to understand how to do in mongoDb query ($project).
Here is a possible approach
First $unwind the configs since it contains only 1 element
In the $project stage use $arrayToObject to convert the [{k:'key1',v:'value1'},{k:'key2',v:'value2'}] to {key1:'value1',key2:'value2'}.
The $map stage is used to convert the field names in values array to the above format.
$concatArrays is used to concat the name field and value before converting array to object so that it becomes [{k:'name',v:'Shubham'},{k:'Height',v:'172cm'}...]
Playground Link
db.collection.aggregate([
{
$unwind: "$configs"
},
{
$project: {
date: 1,
configs: {
$arrayToObject: {
$concatArrays: [
{
$map: {
input: "$configs.values",
as: "el",
in: {
k: "$$el.type",
v: "$$el.text"
}
}
},
[
{
k: "name",
v: "$configs.name"
}
]
]
},
},
},
},
])
Did you try this?
arr=[];
yourOutPutJson.forEach(function(b){var obj={};obj.name=b.configs[0].name;b.configs[0].values.forEach(function(c){obj[c.type]=c.text});arr.push(obj)});

Find specific field in MongoDB document based on condition

I have the following MongoDB documents like this one:
{
"_id": "ABC",
"properties":
[
{
"_id": "123",
"weight":
{
"$numberInt": "0"
},
"name": "Alice"
},
{
"_id": "456",
"weight":
{
"$numberInt": "1"
},
"name": "Bob"
},
{
"_id": "789",
"weight":
{
"$numberInt": "1"
},
"name": "Charlie"
}
]
}
And I would like to find the _id of the property with name "Alice", or the _id of the property with "$numberInt": "0".
I'm using pymongo.
The following approach:
from pymongo import MongoClient
mongo_client = MongoClient("mymongourl")
mongo_collection = mongo_client.mongo_database.mongo_collection
mongo_collection.find({'properties.name': 'Alice'}, {'properties': 1})[0]['_id']
Gives the very first _id ("123")
But since I filtered for the document, if Alice was in the second element of the properties array (_id: "456") I would have missed her.
Which is the best method to find for the specific _id associated with the element with the specified name?
You can simply use $reduce to iterate through the properties array. Conditionally store the _id field if it matches your conditions.
db.collection.aggregate([
{
"$addFields": {
"answer": {
"$reduce": {
"input": "$properties",
"initialValue": null,
"in": {
"$cond": {
"if": {
$or: [
{
$eq: [
"$$this.name",
"Alice"
]
},
{
$eq: [
"$$this.weight",
0
]
}
]
},
"then": "$$this._id",
"else": "$$value"
}
}
}
}
}
}
])
Mongo Playground

How to count embedded array object elements in mongoDB

{
"orderNo": "123",
"bags": [{
"type": "small",
"products": [{
"id": "1",
"name": "ABC",
"returnable": true
}, {
"id": "2",
"name": "XYZ"
}
]
},{
"type": "big",
"products": [{
"id": "3",
"name": "PQR",
"returnable": true
}, {
"id": "4",
"name": "UVW"
}
]
}
]
}
I have orders collection where documents are in this format. I want to get a total count of products which has the returnable flag. e.g: for the above order the count should be 2. I am very new to MongoDB wanted to know how to write a query to find this out, I have tried few things but did not help:
this is what I tried but not worked:
db.orders.aggregate([
{ "$unwind": "$bags" },
{ "$unwind": "$bags.products" },
{ "$unwind": "$bags.products.returnable" },
{ "$group": {
"_id": "$bags.products.returnable",
"count": { "$sum": 1 }
}}
])
For inner array you can use $filter to check returnable flag and $size to get number of such items. For the outer one you can take advantage of $reduce to sum the values from inner arrays:
db.collection.aggregate([
{
$project: {
totalReturnable: {
$reduce: {
input: "$bags",
initialValue: 0,
in: {
$add: [
"$$value",
{
$size: {
$filter: {
input: "$$this.products",
as: "prod",
cond: {
$eq: [ "$$prod.returnable", true ]
}
}
}
]
}
}
}
}
}
}
])
Mongo Playground

Add field to every object in array of objects in mongo aggregation

I have one field in schema at root level and want to add it in every object from array which matches a condition.
Here is a sample document....
{
calls: [
{
"name": "sam",
"status": "scheduled"
},
{
"name": "tom",
"status": "cancelled"
},
{
"name": "bob",
"status": "scheduled"
},
],
"time": 1620095400000.0,
"call_id": "ABCABCABC"
}
Required document is as follows:
[
{
"call_id": "ABCABCABC",
"calls": [
{
"call_id": "ABCABCABC",
"name": "sam",
"status": "scheduled"
},
{
"name": "tom",
"status": "cancelled"
},
{
"call_id": "ABCABCABC",
"name": "bob",
"status": "scheduled"
}
],
"time": 1.6200954e+12
}
]
The call_id should be added to all objects in array whose status is "scheduled".
Is it possible to do this with mongo aggregation? I have tried $addFields but was unable to achieve above result.
Thanks in advance!
Here is how I would do it using $map and $mergeObjects
db.collection.aggregate([
{
"$addFields": {
calls: {
$map: {
input: "$calls",
as: "call",
in: {
$cond: [
{
$eq: [
"$$call.status",
"scheduled"
]
},
{
"$mergeObjects": [
"$$call",
{
call_id: "$call_id"
}
]
},
"$$call"
]
}
}
}
}
}
])
Mongo Playground