Delete a value in a collection Mongo. Example attached - mongodb

I have this document inside a collection in Mongo and I would like to delete the "7552" : "RTEST" in de bakendData and "7552" in data. How could do it using commands?
{
"_id" : ObjectId("xxxxxx"),
"contractId" : "55528fxxxxxxxxxxxx",
"field1": [
{
"name":"example",
"backendData": {
"map": {
"7552" : "RTEST",
"3511" : "TESTR",
"5312" : "JKTLE",
"5310" : "INVTS"
}
},
"data": {
"defaultOrder": [
"7552",
"3511",
"5312",
"5310"
]
}
}
]
}
Desired result:
{
"_id" : ObjectId("xxxxxx"),
"contractId" : "55528fxxxxxxxxxxxx",
"field1": [
{
"name":"example",
"backendData": {
"map": {
"3511" : "TESTR",
"5312" : "JKTLE",
"5310" : "INVTS"
}
},
"data": {
"defaultOrder": [
"3511",
"5312",
"5310"
]
}
}
]
}
I try something like that but it doesn't work:
db.collection.update(
{ contractId: "55528..............." },
{ $pull: {field1: [ { backendData: { map: {7552: "RTEST"} } }] }}
);
Also I would like to add new values. Example:
"backendData": {
"map": {
"3511" : "TESTR",
"5312" : "JKTLE",
"5310" : "INVTS",
"5355" : "IRZTS",
}
},
"data": {
"defaultOrder": [
"3511",
"5312",
"5310",
"5355"
]
}
Can someone help me?
Thank in advance
I attached an image with the document in Robot 3T

I expect someone will provide a much shorter answer, but here's one way to remove and add the items you want with one update.
db.collection.update({
// match the doc by _id
"_id": ObjectId("55528f000000000000000000")
},
[
{ // rebuild field1
"$set": {
"field1": {
"$map": {
"input": "$field1",
"in": {
// merge what's there plus filtered map plus new object
"$mergeObjects": [
"$$this",
{ "backendData": {
"map": {
"$mergeObjects": [
{ "$arrayToObject": {
"$filter": {
"input": {
"$objectToArray": "$$this.backendData.map"
},
"as": "stuff",
"cond": {
// keep everything except object with 7552 key
"$ne": [ "$$stuff.k", "7552" ]
}
}
}
},
{ "5355": "IRZTS" }
]
}
}
},
{ "data": {
"defaultOrder": {
"$concatArrays": [
{ "$filter": {
"input": "$$this.data.defaultOrder",
"as": "someNum",
"cond": {
// keep everything except 7552
"$ne": [ "$$someNum", "7552" ]
}
}
},
[ "5355" ]
]
}
}
}
]
}
}
}
}
}
])
Try it on mongoplayground.net.

Related

Zip two array and create new array of object

hello all i'm working with a MongoDB database where each data row is like:
{
"_id" : ObjectId("5cf12696e81744d2dfc0000c"),
"contributor": "user1",
"title": "Title 1",
"userhasRate" : [
"51",
"52",
],
"ratings" : [
4,
3
],
}
and i need to change it to be like:
{
"_id" : ObjectId("5cf12696e81744d2dfc0000c"),
"contributor": "user1",
"title": "Title 1",
rate : [
{userhasrate: "51", value: 4},
{userhasrate: "52", value: 3},
]
}
I already try using this method,
db.getCollection('contens').aggregate([
{ '$group':{
'rates': {$push:{ value: '$ratings', user: '$userhasRate'}}
}
}
]);
and my result become like this
{
"rates" : [
{
"value" : [
5,
5,
5
],
"user" : [
"51",
"52",
"53"
]
}
]
}
Can someone help me to solve my problem,
Thank you
You can use $arrayToObject and $objectToArray inside $map to achieve the required output.
db.collection.aggregate([
{
"$project": {
"rate": {
"$map": {
"input": {
"$objectToArray": {
"$arrayToObject": {
"$zip": {
"inputs": [
"$userhasRate",
"$ratings"
]
}
}
}
},
"as": "el",
"in": {
"userhasRate": "$$el.k",
"value": "$$el.v"
}
}
}
}
}
])
Alternative Method
If userhasRate contains repeated values then the first solution will not work. You can use arrayElemAt and $map along with $zip if it contains repeated values.
db.collection.aggregate([
{
"$project": {
"rate": {
"$map": {
"input": {
"$zip": {
"inputs": [
"$userhasRate",
"$ratings"
]
}
},
"as": "el",
"in": {
"userhasRate": {
"$arrayElemAt": [
"$$el",
0
]
},
"value": {
"$arrayElemAt": [
"$$el",
1
]
}
}
}
}
}
}
])
Try below aggregate, first of all you used group without _id that grouped all the JSONs in the collection instead set it to "$_id" also you need to create 2 arrays using old data then in next project pipeline concat the arrays to get desired output:
db.getCollection('contens').aggregate([
{
$group: {
_id: "$_id",
rate1: {
$push: {
userhasrate: {
$arrayElemAt: [
"$userhasRate",
0
]
},
value: {
$arrayElemAt: [
"$ratings",
0
]
}
}
},
rate2: {
$push: {
userhasrate: {
$arrayElemAt: [
"$userhasRate",
1
]
},
value: {
$arrayElemAt: [
"$ratings",
1
]
}
}
}
}
},
{
$project: {
_id: 1,
rate: {
$concatArrays: [
"$rate1",
"$rate2"
]
}
}
}
])

MongoDB - Performing an upsert on an array if arrayFilters are not satisfied

I have the following document stored in mongo:
{
"_id" : ObjectId("5d1a08d2329a3c1374f176df"),
"associateID" : "1234567",
"associatePreferences" : [
{
"type" : "NOTIFICATION",
"serviceCode" : "service-code",
"eventCode" : "test-template",
"preferences" : [
"TEXT",
"EMAIL"
]
},
{
"type" : "URGENT_NOTIFICATION",
"serviceCode" : "service-code",
"eventCode" : "test-template",
"preferences" : [
"TEXT"
]
}
]
}
I am basically trying to query one of the elements of the associatePreferences array based off of its type, serviceCode, and eventCode and add a new value to the preferences array. However, if that combination of type, serviceCode, and eventCode is not present, I would like to add a new element to the associatePreferences array with those values. This is my current query:
db.user_communication_preferences.update(
{'associateID':'testassociate'},
{$addToSet:{'associatePreferences.$[element].preferences':"NEW_VALUE"}},
{arrayFilters:[{'element.serviceCode':'service-code-not-present', 'element.eventCode':'event-code-not-present','element.type':'URGENT_NOTIFICATION'}]}
)
This query works if all of the arrayFilters are present in the an element of associatePreferences, but it does not add a new element if it is not present. What am I missing?
You can use aggregation pipeline to check the existence of the element, then append the element to associatePreferences array conditionally. Finally, using the aggregation result to update back your document.
db.user_communication_preferences.aggregate([
{
"$match": {
"associateID": "testassociate"
}
},
{
"$addFields": {
"filteredArray": {
"$filter": {
"input": "$associatePreferences",
"as": "pref",
"cond": {
$and: [
{
$eq: [
"$$pref.type",
"URGENT_NOTIFICATION"
]
},
{
$eq: [
"$$pref.eventCode",
"event-code-not-exists"
]
},
{
$eq: [
"$$pref.serviceCode",
"service-code-not-exists"
]
}
]
}
}
}
}
},
{
$addFields: {
"needAddElement": {
$eq: [
{
"$size": "$filteredArray"
},
0
]
}
}
},
{
"$addFields": {
"associatePreferences": {
"$concatArrays": [
"$associatePreferences",
{
"$cond": {
"if": {
$eq: [
"$needAddElement",
true
]
},
"then": [
{
"type": "URGENT_NOTIFICATION",
"serviceCode": "service-code-not-exists",
"eventCode": "event-code-not-exists",
"preferences": [
"TEXT"
]
}
],
"else": []
}
}
]
}
}
}
]).forEach(result){
db.user_communication_preferences.update({
_id : result._id
}, {
$set: {
"associatePreferences" : result.associatePreferences
}
})
}

MongoDB: Get only specific fields in nested array documents

I'm trying to project the values from nested array documents which are in the below format. What I expect is to display only the specValue of the specific specType selected in the find query.
{
"carId": "345677"
"car" : {
"model" : [
{
"specs" : [
{
"specType": "SEDAN"
"specValue" : "1"
},
{
"specType": "BR_INC"
"specValue" : "yes"
},
{
"specType": "PLAN"
"specValue" : "gold"
}
]
}
]
}
}
This is what I have tried.
db.cars.find({carId:'345677','car.model.specs.specType':'SEDAN'},{'car.model.specs.specValue':1})
This approach gives me the all the specValues instead like below.
{
"carId": "345677"
"car" : {
"model" : [
{
"specs" : [
{
"specValue" : "1"
},
{
"specValue" : "yes"
},
{
"specValue" : "gold"
}
]
}
]
}
}
How do I make this right to get in the right format like this. Could anyone please help.
{
"carId": "345677"
"car" : {
"model" : [
{
"specs" : [
{
"specType": "SEDAN"
"specValue" : "1"
}
]
}
]
}
}
You can use below aggregation
db.collection.aggregate([
{ "$project": {
"car": {
"model": {
"$filter": {
"input": {
"$map": {
"input": "$car.model",
"in": {
"specs": {
"$filter": {
"input": "$$this.specs",
"cond": { "$eq": ["$$this.specType", "SEDAN"] }
}
}
}
}
},
"cond": { "$ne": ["$$this.specs", []] }
}
}
}
}}
])

Filter the sub array of an array by some criteria

Hi have a document in the format :
{
"_id":"someId",
"someArray":[
{
"subId":1,
"subArray":[
{
"field1":"A",
"filterMe":"NO"
},
{
"field1":"B",
"filterMe":"YES"
}
]
},
{
"subId":2,
"subArray":[
{
"field1":"C",
"filterMe":"YES"
},
{
"field1":"D",
"filterMe":"NO"
}
]
}
]
}
how can i filter the subArray based on some criteria. Example filter out the subArray if field filterMe is "YES". so finally the output json should be like
{
"_id":"someId",
"someArray":[
{
"subId":1,
"subArray":[
{
"field1":"A",
"filterMe":"NO"
}
]
},
{
"subId":2,
"subArray":[
{
"field1":"D",
"filterMe":"NO"
}
]
}
]
}
I tried in the below way but, its filtering the whole subArray.
db.testJson.aggregate([
{ $project: {
'someArray.subArray': {
$filter: {
input: '$someArray.subArray',
as: 'input',
cond: {$eq: ["$$input.filterMe", "YES"]}
}}
}}
]);
You just need a $filter inside a $map:
db.junk.aggregate([
{ "$project": {
"someArray": {
"$filter": {
"input": {
"$map": {
"input": "$someArray",
"as": "some",
"in": {
"subId": "$$some.subId",
"subArray": {
"$filter": {
"input": "$$some.subArray",
"as": "sub",
"cond": { "$ne": [ "$$sub.filterMe", "YES" ] }
}
}
}
}
},
"as": "some",
"cond": { "$gt": [ { "$size": "$$some.subArray" }, 0 ] }
}
}
}}
])
Produces:
{
"_id" : "someId",
"someArray" : [
{
"subId" : 1,
"subArray" : [
{
"field1" : "A",
"filterMe" : "NO"
}
]
},
{
"subId" : 2,
"subArray" : [
{
"field1" : "D",
"filterMe" : "NO"
}
]
}
]
}
I actually wrap that in an additional $filter to remove any someArray entries where the filtered subArray ended up being empty as a result. Mileage may vary on that being what you want to do.

Mongo aggregation $filter on true/false is not working

I have the following data
{
"_id":"57b5271231a5a203f8815e78",
"name":"Group A",
"created":new Date(1471489810155),
"active":true,
"invites":[
],
"requests":[
{
"_id":"57b683e531a5a21679b78e6c",
"created":new Date(1471579109215),
"user_id":"57b4c5f0291ebb23110b888e",
"description":"Request From John",
"active":true,
"date": new Date("2016-08-23T13:58:15-0700 "),
" denied_users":[
]
},
{
"_id":"57b683e531a5a21679a78e6c",
"created":new Date(1471579109215),
"user_id":"57b4c5f0291ebb13110b888e",
"description":"Request A",
"active":true,
"date": new Date("2016-08-23T13:58:15-0700 "),
" denied_users":[
]
},
{
"_id":"57b6841231a5a21679a78e6d",
"created":new Date(1471579154271),
"user_id":"57b4c5f0291ebb13110b888e",
"description":"Request B",
"active":true,
"date": new Date("2016-08-26T13:59:07-0700 "),
" denied_users":[
]
}
],
"fulfillments":[
]
}
And am running the following query to Retrieve all embedded Request objects that have active = true. Nothing is being returned though.
db.groups.aggregate(
[
{ $project : { "requests" : 1 }},
{ $unwind : "$requests" },
{ $project: {
"requests": {
"$filter": {
"input": "$requests",
"as": "item",
"cond": { $eq: [ "$$item.active",true ] }
}
}
}
}
]
)
What am I doing wrong?
UPDATE
Would it be easier(the same) if I did the following
[
{ $project : { "requests" : 1 }},
{ $unwind : "$requests" },
{ $match : { "requests.active" : true } }
]
You just need to remove the $unwind stage from your pipeline:
db.groups.aggregate(
[
{ $project: {
"requests": {
"$filter": {
"input": "$requests",
"as": "item",
"cond": { $eq: [ "$$item.active",true ] }
}
}
}
}
]
)
Otherwise the $unwind changes the requests field from an array into a single object as it duplicates the docs which can't be used with $filter.