Mongo - Remove Array Element with $pull Does Not Work With $nin (does not exist) - arrays

I have the following query and it works with $in but not with $nin.
I'm trying to remove the link list items by name (itemA and itemB) from all records that are NOT part of a document that has a user name which contains '#not_these' or '#nor_these'.
db.users.update({userName:{$nin: [ RegExp('#not_these.com'), RegExp('#nor_these.com') ]}},{$pull:{'myLinkList': {name: {$in: ['itemA', 'itemB']} } } } )
If I make it $in and and declare the RegExp() explicitly it does remove the array items as expected.
db.users.update({userName:{$in: [ RegExp('#yes_these.com'), RegExp('#and_these.com') ]}},{$pull:{'myLinkList': {name: {$in: ['itemA', 'itemB']} } } } )
This one does remove itemA and itemB array list items for those explicitly declared users.
Why can't the items '#yes_these' and '#and_these' be removed using the first example? It seems to do nothing when executed.
Sample document:
{
"_id": ObjectId('5e34741aa18d8a0c24078b61'),
"myLinkList": [
{
"name": "item",
"created": ISODate('2020-01-31T18:38:18.682Z'),
"managedBy": [
"imm"
]
},
{
"name": "itemA",
"created": ISODate('2020-01-31T18:38:18.682Z'),
"managedBy": [
"imm"
]
},
{
"name": "itemB",
"created": ISODate('2020-01-31T18:38:18.682Z'),
"managedBy": [
"imm"
]
}
],
"userName": "#yes_these.com"
}
After update (hopefully):
{
"_id": ObjectId('5e34741aa18d8a0c24078b61'),
"myLinkList": [
{
"name": "item",
"created": ISODate('2020-01-31T18:38:18.682Z'),
"managedBy": [
"imm"
]
}
],
"userName": "#yes_these.com"
}

I verified this did work:
db.users.updateMany({userName:{$nin: [ /#not_these\.com/), /#nor_these\.com/) ]}},{$pull:{'myLinkList': {name: {$in: ['itemA', 'itemB']} } } } )

Related

Mongo Query to modify the existing field value with new value + array of objects

I want to update many documents based on the condition in MongoDB.
MODEL is the collection which has the document with below information.
"info": [
{
"field1": "String1",
"field2": "String2"
},
{
"field1": "String1",
"field2": "String_2"
}
],
"var": "x"
I need to update all the "String1" value of field1 with "STRING_NEW". I used the below query to update but not working as expected.
db.model.updateMany(
{ "info.field1": { $exists: true } },
[
{ "$set": {
"info": {
"$map": {
"input": "$info.field1",
"in": {
"$cond": [
{ "$eq": ["$$this.field1", "String1"] },
"STRING_NEW",
$$this.field1
]
}
}
}
} }
]
)
Please have a look and suggest if anything is to be modified in the above query.
Solution 1
With the update with aggregation pipeline, you should iterate the object in info array and update the iterated object by merging the current object with new field1 field via $mergeObjects.
db.model.updateMany({
"info.field1": "String1"
},
[
{
"$set": {
"info": {
"$map": {
"input": "$info",
"in": {
"$cond": [
{
"$eq": [
"$$this.field1",
"String1"
]
},
{
$mergeObjects: [
"$$this",
{
"field1": "STRING_NEW"
}
]
},
"$$this"
]
}
}
}
}
}
])
Demo Solution 1 # Mongo Playground
Solution 2
Can also work with $[<identifier>] positional filtered operator and arrayFilters.
db.model.updateMany({
"info.field1": "String1"
},
{
"$set": {
"info.$[info].field1": "STRING_NEW"
}
},
{
arrayFilters: [
{
"info.field1": "String1"
}
]
})
Demo Solution 2 # Mongo Playground

Return document where array element includes all values of input array | MongoDB

I have a collection of exercises:
[
{
"name": "Push Ups",
"muscleGroups": ["Chest", "Shoulders", "Abs", "Biceps"]
},
{
"name": "Sit Ups",
"muscleGroups": ["Abs"]
},
{
"name": "Pull Ups",
"muscleGroups": ["Abs", "Biceps", "Back"]
}
]
and an input array of inputMuscleGroups. I am trying to filter the exercises to where the muscleGroups array of the document has every element of the inputMuscleGroups.
For inputMuscleGroups = ["Abs"], every document would return.
For inputMuscleGroups = ["Abs", "Biceps"], output would be:
[
{
"name": "Push Ups",
"muscleGroups": ["Chest", "Shoulders", "Abs", "Biceps"]
},
{
"name": "Pull Ups",
"muscleGroups": ["Abs", "Biceps", "Back"]
}
]
For inputMuscleGroups = ["Abs", "Shoulders", "Chest"], output would be:
[
{
"name": "Push Ups",
"muscleGroups": ["Chest", "Shoulders", "Abs", "Biceps"]
}
]
I have played around with $in but it appears these only return true if any of the input arrays match any of the document array.
Ideally I would want to do this within a .find() method as opposed to a .aggregate() method.
You can simply use $all
db.collection.find({
muscleGroups: {
$all: [
"Abs",
"Biceps"
]
}
})
Working Mongo playground

Dictionary to Array of Objects

I have a dictionary field in my data like so:
"details": {
"code": "PPIO",
"product": [{
"productCode": "ADGT"
}]
}
I need to convert the field to an array of objects:
"details":
[
{
"code": "PPIO",
"product": [{
"productCode": "ADGT"
}]
}
]
You can use $addFields to overwrite existing field:
db.collection.aggregate([
{
$addFields: {
details: [ "$details" ]
}
}
])
Mongo Playground
EDIT:
For update you can use below syntax:
db.col.updateMany({}, [{ $set: { details: [ "$details" ] } }])
EDIT 2:
Alternatively, if updateMany doesn't work for you, you can use $out operator which will replace your collection entirely with an aggregation outcome:
db.collection.aggregate([
{
$addFields: {
details: [ "$details" ]
}
},
{ $out: "collection" }
])

Find array in array data in MongoDB

I want find in this document groups:
"document": {
"groups": [
{
"id": "5ccd5f7f34f82b0e3315b2f6"
},
{
"id": "73b43unbfkfmdmddfdf84jjk"
}
]
}
are contains some of my query array groups ID:
[ '5ccd5f7f34f82b0e3315b2f6',
'5cdeded7ace07216f5873b5d',
'5cdee5d114edac2cc00bb333' ]
A simple find query suffices:
db.collection.find({ 'groups.id' : {$in : [ '5ccd5f7f34f82b0e3315b2f6',
'5cdeded7ace07216f5873b5d',
'5cdee5d114edac2cc00bb333' ] }})

Update array content within another array that don't have key

I have mongoDB content as below:
[
{
"_id":{
"$oid":"57c6699711bd6a0976cabe8a"
},
"ID":"1111",
"FullName":"AAA",
"Category":[
{
"CategoryId":{
"$oid":"57c66ebedcba0f63c1ceea51"
},
"_id":{
"$oid":"57e38a8ad190ea1100649798"
},
"Value":[
{
"Name":""
}
]
},
{
"CategoryId":{
"$oid":"57c3df061eb1e59d3959cc40"
},
"_id":{
"$oid":"57e38a8ad190ea1100649797"
},
"Value":[
[
"111",
"XXXX",
"2005"
],
[
"1212",
"YYYY",
"2000"
],
[
"232323",
"ZZZZZ",
"1999"
]
]
}
]
},
{
"_id":{
"$oid":"57c6699711bd6a0976cabe8a"
},
"ID":"1111",
"FullName":"BBB",
"Category":[
{
"CategoryId":{
"$oid":"57c66ebedcba0f63c1ceea51"
},
"_id":{
"$oid":"57e38a8ad190ea1100649798"
},
"Value":[
{
"Name":""
}
]
},
{
"CategoryId":{
"$oid":"57c3df061eb1e59d3959cc40"
},
"_id":{
"$oid":"57e38a8ad190ea1100649797"
},
"Value":[
[
"4444",
"XXXX",
"2005"
],
[
"7777",
"GGGG",
"2000"
],
[
"8888",
"ZZZZZ",
"1999"
]
]
}
]
}
]
Here I have an array named 'Category' where it contains objects with different category id.
I need to
select a particular category id - '57c3df061eb1e59d3959cc40'
From the above selected Category, we get 'Value' array
From Value array need to find if the second value is equal to 'ZZZZZ' ie. value[1] == 'ZZZZZ'
And now, update the matched value arrays with a new value at the end
Eg:
[
"232323",
"ZZZZZ",
"1999"
]
should be updated to
[
"232323",
"ZZZZZ",
"1999",
"update1"
]
and
[
"8888",
"ZZZZZ",
"1999"
]
should be updated to
[
"8888",
"ZZZZZ",
"1999",
"update1"
]
I have tried as below:
resume.update({
"Category.CategoryId": new ObjectId('57c3df191eb1e59d3959cc43'),
"Category.Value.$.1": 'ZZZZZ'
},
{"$set": {"Category.Value.$.3": "update1"}
}, function(err, resData){
res.send(resData);
});
But, nothing gets updated. Its there any way to get this work. Please help to update the inner array.
Thanks in advance.
Your goal is not possible at the moment since you need to update two positional elements.
There is a JIRA trackable for the sort of behaviour you want here: https://jira.mongodb.org/browse/SERVER-831
It's a problem since you need to match two elements positions:
the Category element with the matched CategoryId
the Value element in the Value array of arrays
If one of these wouldn't be an array it would have been possible.
Anyway, Your update try above was wrong. IF this feature was possible (and it is not!!!) it would have been something like this:
db.resume.update(
{
Category: {
$elemMatch: {
CategoryId: ObjectId('57c3df061eb1e59d3959cc40'),
Value: {
$elemMatch: {
'1': 'ZZZZZ'
}
}
}
}
},
{
$push: {
'Category.$.Value.$': 'update1'
}
}
)
The positional $ operator should be used during the update and not the find like you did, and it will update the first element that matched the query.
Doing the above will return the error:
Too many positional (i.e. '$') elements found in path 'Category.$.Value.$'
Because of the missing feature I explained at the top.
So, currently (version 3.2) you will not be able to do this unless you change your schema.

Resources