Dictionary to Array of Objects - arrays

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" }
])

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

How to $match an item from the list

I am trying to display the items, that have specific name brand.
This is how that field looks like:
"brand" : [
[
"Samsung",
"Iphone",
"Huawei"
]
]
Tried that query, but I get 0 results:
db.collection.aggregate([{$match: { brand: "Samsung" }}])
Any ideas, what's wrong?
Your data model is an array of arrays so you have to deal with two dimensions. You can use $map along with $in first and then use $anyElementTrue to see if there's any sub-array matching your condition:
db.collection.aggregate([
{
$match: {
$expr: {
$anyElementTrue: {
$map: {
input: "$brand",
in: { $in: [ "Samsung", "$$this" ] }
}
}
}
}
},
{
$project: {
_id: 1,
color: 1
}
}
]);
Mongo Playground
EDIT: use $project to display only certain fields

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

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']} } } } )

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' ] }})

Aggregate - $push an Array Expression in $group

I have this aggregation pipeline:
{
$project: {
type: '$_id.type',
datapoints: [
{$multiply: ['$_id.timestamp', 1000]},
'$count',
],
},
},
{
$group: {
_id: {
type: '$type',
},
datapoints: {$push: '$datapoints'},
},
},
... which brought me to a following question:
How could I possibly append/push/add/etc an array to datapoints in $group (what could let me avoid $project stage))?
If I try putting the same expression for datapoints in the $project under $push in the $group it gives me an error
It's a fair point because you cannot just simply notate with "bracket" [] notation as available from MongoDB 3.2 into a $push.
It's a bit of a hack, but you can basically wrap the expression with $map instead of using the [] notation:
{ "$group": {
"_id": "$_id.type",
"datapoints": {
"$push": {
"$map": {
"input": [1],
"in": [
{ "$multiply": ["$_id.timestamp", 1000] },
"$count"
]
}
}
}
}}
Or even $concatArrays if your MongoDB supports it:
{ "$group": {
"_id": "$_id.type",
"datapoints": {
"$push": {
"$concatArrrays": [
[
{ "$multiply": ["$_id.timestamp", 1000] },
"$count"
]
]
}
}
}}
Or even $setUnion, which is actually probably the shortest to type, but it may not retain the order of elements if that is important to you:
{ "$group": {
"_id": "$_id.type",
"datapoints": {
"$push": {
"$setUnion": [
[
{ "$multiply": ["$_id.timestamp", 1000] },
"$count"
]
]
}
}
}}
Trying to simply do :
"datapoint": { "$push": [{ "$mulitply": [ ...
Will of course result in an error
"errmsg" : "The $push accumulator is a unary operator",
And this sort of expression would be syntactically incorrect:
"datapoint": { "$push": { ["a"] }
So you need an "expression" of some sort which is "unary" and not "list based" and returns a BSON Array in result. The above operators cover those cases.

Resources