How to create an array inside root element on mongodb - arrays

I have this data that i moddeling after i imported a csv file:
{Main: {
"Name" : "MainNAme1",
"age" : "age1",
"ge" :"ge1",
{Crs:{[
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE",
}},
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100",
}},
]}},
}}
And i would like to know how can i create an new array inside a root element like this:
{Main: {
"Name" : "MainNAme1",
"info":[{
"age" : "age1",
"ge" :"ge1",
}],
{Crs:{[
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE",
}},
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100",
}},
]}},
}}
I'm using aggregate to moddeling this.

Going off your OP. You are looking to move age and ge into its own array. You could use $addToSet during your $group stage
Try adding this into your $group pipline:
"Info" : { $addToSet : { "age": "$age", "ge" : "$ge" } } }}
output
"Info" : [
{
"age" : "age1",
"ge" : "ge1"
}]

You're looking for the $addFields stage which is available from MongoDB v3.4 onwards. Before that you'd need to use $project.
db.collection.aggregate({
$addFields: {
"info": [{
"age": "$Main.age",
"ge": "$Main.ge"
}]
}
})

Related

How can i retrieve all the objects from an array based on a query condition?

consider a table 'users' with following data
{ "_id" : ObjectId("5feb55107c844e84252c05db"),
"firstName" : "raj",
"lastName" : "kumar",
"calories_per_day" : 1800,
"phone" : 9955544525,
"email" : "rjkrsngh#yahoo.com",
"username" : "rjkrsngh",
"meals" : [
{
"datetime" : ISODate("2020-12-20T16:00:00Z"),
"food_name" : "pizza",
"calorie" : 400,
"description" : "pizza with extra veggies"
},
{ "datetime" : ISODate("2020-12-21T16:00:00Z"),
"food_name" : "wild salmon burgers",
"calorie" : 250,
"description" : "salmon burger"
},
{ "datetime" : ISODate("2020-12-21T16:00:00Z"),
"food_name" : "pasta",
"calorie" : 250,
"description" : "green sauce pasta"
},
{ "datetime" : ISODate("2020-12-21T12:00:00Z"),
"food_name" : "palak paneer",
"calorie" : 385,
"description" : "green palak paneer"
} ]
}
From this entry, i want to retrieve all the food consumed by user: 'rjkrsngh' on 21-12-2020 which should be:
{ "datetime" : ISODate("2020-12-21T16:00:00Z"),
"food_name" : "wild salmon burgers",
"calorie" : 250,
"description" : "salmon burger"
},
{ "datetime" : ISODate("2020-12-21T16:00:00Z"),
"food_name" : "pasta",
"calorie" : 250,
"description" : "green sauce pasta"
},
{ "datetime" : ISODate("2020-12-21T12:00:00Z"),
"food_name" : "palak paneer",
"calorie" : 385,
"description" : "green palak paneer"
}
using the query:
db.users.find({username:"rjkrsngh"}, {meals: {$elemMatch: {datetime:{$gte:new Date("2020-12-21T00:00:00Z")}}}}).pretty()
i get only the first object that matches the query, which is correct as per documentation of $elemMatch. However, i am not able to figure out a way to get all the objects that matches my query.
I tried aggregation query mentioned below too, but didn't work.
db.users.aggregate([
{ $match: { username: 'rjkrsngh' }},
{ $project: {
meals: { $filter: {
input: '$meals',
as: 'meals',
cond: { $gte: ['$$meals.datetime', 'new Date("2020-12-21T00:00:00Z")']}
}},
_id: 0
}}
]);
Can anyone help me out here!

How to modify fields in specific sub-documents in an array?

I have a collection where each document has an array of sub-documents, containing several fields. I need to update specific sub-documents based on their fields, but every attempt I've done so far changes the field in all of the arrayed sub-documents
Here is some sample data:
{
'_id' : ObjectId('0001'),
'Region' : 'Northern',
"Items" : [
{
"ItemId" : NumberInt(25),
"Name" : "Widget",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000037"
},
{
"ItemId" : NumberInt(30),
"Name" : "Gizmo",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000038"
},
{
"ItemId" : NumberInt(35),
"Name" : "Thingy",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000039"
}
]
}
When I try to use update() with the following query, it updates the ProductType on all array items, not just the one I'm trying to change.
To clarify, I want to change the array item with ItemIdLegacy: "ca-000038" to have ProductType: 20. All other Array items should remain unchanged. Query that I have tried:
db.Collection.update({"Items.ItemIdLegacy" : "ca-000038"},[{$set: { "Items.ProductType" : "20"} }],{multi: false});
This is the desired output:
{
'_id' : ObjectId('0001'),
'Region' : 'Northern',
"Items" : [
{
"ItemId" : NumberInt(25),
"Name" : "Widget",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000037"
},
{
"ItemId" : NumberInt(30),
"Name" : "Gizmo",
"ProductType" : "20",
"ItemIdLegacy" : "ca-000038"
},
{
"ItemId" : NumberInt(35),
"Name" : "Thingy",
"ProductType" : "15",
"ItemIdLegacy" : "ca-000039"
}
]
}
But this is the actual output of running that query:
{
'_id' : ObjectId('0001'),
'Region' : 'Northern',
"Items" : [
{
"ItemId" : NumberInt(25),
"Name" : "Widget",
"ProductType" : "20",
"ItemIdLegacy" : "ca-000037"
},
{
"ItemId" : NumberInt(30),
"Name" : "Gizmo",
"ProductType" : "20",
"ItemIdLegacy" : "ca-000038"
},
{
"ItemId" : NumberInt(35),
"Name" : "Thingy",
"ProductType" : "20",
"ItemIdLegacy" : "ca-000039"
}
]
}
I feel like I'm missing something simple...
EDIT: I have q uery that will allow me to update a single matching element in the array, but I have thousands that would need to be done so one offs don't necessarily work (sure I could parse them all out and spam them to the shell, but I want something more elegant)
Single Element Update:
db.Collection.updateOne({"Items.ItemIdLegacy" : "ca-000038"},{ $set: { "Items.$.ProductType" : "20" } } );
Try this :-
db.collection.update({
"Items.ItemIdLegacy": "ca-000038"
},
{
$set: {
"Items.$.ProductType": 20
}
},
{
multi: true
})
Here is Working Example

Get index of an element mongodb aggregation

Here is my collection
{
"_id" : ObjectId("5c225f9a66d39d55c036fa66"),
"name" : "Sherlock",
"mobile" : "999999",
"adress" : [
{
"street" : "221b baker street",
"city" : "london"
},
{
"street" : "ben street",
"city" : "london"
}
],
"tags" : [
"Detective",
"Magician",
"Avenger"
]
}
Now I want to get the first or second value inside address array.
for that I'm using this command.
> db.agents.findOne({"name" : "Sherlock"},{"adress" : 1})
but instead of giving a single result it is giving the entire array like
{
"_id" : ObjectId("5c225f9a66d39d55c036fa66"),
"adress" : [
{
"street" : "221b baker street",
"city" : "london"
},
{
"street" : "ben street",
"city" : "london"
}
]
}
It can be done by comparing array value like
db.agents.find({"adress.street": "ben street"}, {_id: 0, 'adress.$': 1});
But I don't want to compare just to print the array indexes. How can I get the single result?
Any help is appreciated..
You can use $arrayElemAt to get the specific element from the array
db.collection.aggregate([
{ $addFields: { "$arrayElemAt": ["$adress", 0] }} //index
])
and if you want to get the sliced element then you can use $slice projection
db.collection.find({}, { adress: { $slice: [2, 1] }}) // 2 index and 1 number of element
You can $unwind with includeArrayIndex to get the index of address array
db.t11.aggregate([
{$match : {"adress.street" : "ben street"}},
{$unwind : {path : "$adress", includeArrayIndex : "idx"}},
{$match : {"adress.street" : "ben street"}}
]).pretty()
you can add $project to filter the fields not required
result
> db.t11.aggregate([{$match : {"adress.street" : "ben street"}},{$unwind : {path : "$adress", includeArrayIndex : "idx"}},{$match : {"adress.street" : "ben street"}}]).pretty()
{
"_id" : ObjectId("5c225f9a66d39d55c036fa66"),
"name" : "Sherlock",
"mobile" : "999999",
"adress" : {
"street" : "ben street",
"city" : "london"
},
"tags" : [
"Detective",
"Magician",
"Avenger"
],
"idx" : NumberLong(1)
}
>

How to remove a field from an array using aggregate on MongoDB?

{Crs:{[
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE",
}},
{Cr: {
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100",
}},
]}}
I have this data that i model using aggregate and I would like to know how can i remove "DC" field from all elements of the array using aggregate.
>db.crs.aggregate(
[
{$group : {_id : null, crs : {$push : {cr : "$$ROOT"}}}},
{$project : {_id : 0}}
]
)
This is what did to model that data.
I think its something related with $project.
First of all, your document is not a valid JSON schema. You might reconsider the following schema for that particular document.
{
Crs:[
{
"_id" : ObjectId("5a75baada0f20bd4e612d480"),
"Number" : 400,
"Page" : 24,
"DC" : "NE"
},
{
"_id" : ObjectId("5a75baada0f20bd4e612d489"),
"Number" : 300,
"Page" : 14,
"DC" : "100"
}
]
}
Having above schema, you can easily remove DC field using $unset aggregate operator.
db.crs.aggregate([{$unset: 'Crs.DC'}]);

Reformat MongoDB results from aggregate

I'm coming from SQL world and starting with MongoDB, I'm still a bit confused...
I have a collection with this structure
{
"_id" : ObjectId("5769b51f675e6190119935ec"),
"city" : "City1",
"company" : "Company1",
"country" : "Country1",
"zip" : "23345",
},{
"_id" : ObjectId("5769b51f675e6190119935ed"),
"city" : "City1",
"company" : "Company2",
"country" : "Country1",
"zip" : "1245",
},{
"_id" : ObjectId("5769b51f675e6190119935ee"),
"city" : "City2",
"company" : "Company1",
"country" : "Country1",
"zip" : "123445",
},{
"_id" : ObjectId("5769b51f675e6190119935ef"),
"city" : "City1",
"company" : "Company2",
"country" : "Country1",
"zip" : "1235445",
}
and my query,
db.getCollection('stores').aggregate([{"$group":{"_id" : {city :"$city", company : "$company"}}}])
I'm using angular and NodejS+Express to get the data from de database and I get the data with this format
[
{
_id:{
city:"City1",
company:"Compnay1"
}
},
{
_id:{
city:"City1",
company:"Company2"
}
},
{
_id:{
city:"City2",
company:"Compan1"
}
}
]
So I'm wondering if there's a way to get this query result without the _id key,
like this:
[
{
city:"City1",
company:"Compnay1"
},
{
city:"City1",
company:"Company2"
},
{
city:"City2",
company:"Compan1"
}
]
Just use $project as aggregation pipeline operator in the next pipeline stage:
db.getCollection('stores').aggregate([
{"$group":{"_id" : {city :"$city", company : "$company"}}},
{"$project": {"city": "$_id.city", "company": "$_id.company", "_id": 0}}
])

Resources