How to find document with some keys without duplicate value? - mongodb

I have a document Keelung that has an array movie with 6 object.
I want find the document db.getCollection('Keelung').find({}) but without duplicate value in enName.
For instance, if there are two enName value is Truth or Dare, my query command will return 5 objects.
I have no idea how to achieve it, try db.getCollection('Keelung').find({ enName : true, dropDups : true }) is not right obviously.
Is any way to achieve it in mongodb ? Or i should filter it in front end ?
Any help would be appreciated. Thanks in advance.
According #Sergio suggest and i google find $addToSe
db.getCollection('Keelung').aggregate([
{ $unwind: '$data' },
{ $group: { _id: '$_id', movie: { $addToSet: '$enName' } } }
]);
Nothing happened, i have no idea how to use find query in this command...

You need $group aggregation here
db.getCollection('Keelung').aggregate([
{ "$unwind": '$movie' },
{ "$group": {
"_id": "$movie.enName",
"data": {
"$push": {
"field1": "$field1",
"field2": "$field2",
...
}
}
}}
]);

Related

How do I sort results based on a specific array item in MongoDB?

I have an array of documents that looks like this:
patient: {
conditions: [
{
columnToSortBy: "value",
type: "PRIMARY"
},
{
columnToSortBy: "anotherValue",
type: "SECONDARY"
},
]
}
I need to be able to $sort by columnToSortBy, but using the item in the array where type is equal to PRIMARY. PRIMARY is not guaranteed to be the first item in the array every time.
How do I set my $sort up to accommodate this? Is there something akin to:
// I know this is invalid. It's for illustration purposes
$sort: "columnToSortBy", {$where: {type: "PRIMARY"}}
Is it possible to sort a field, but only when another field matches a query? I do not want the secondary conditions to affect the sort in any way. I am sorting on that one specific element alone.
You need to use aggregation framework
db.collection.aggregate([
{
$unwind: "$patient.conditions" //reshape the data
},
{
"$sort": {
"patient.conditions.columnToSortBy": -1 //sort it
}
},
{
$group: {
"_id": "$_id",
"conditions": { //re group it
"$push": "$patient.conditions"
}
}
},
{
"$project": { //project it
"_id": 1,
"patient.conditions": "$conditions"
}
}
])
Playground

Implementing an index that would improve a query in mongoDB

I'm currently struggling to implement an index to my query.
Here is the original query:
*db.getCollection('products').aggregate([
{ $unwind: "$categories" },
{ $unwind: "$categories"},
{$group: {"_id": "$_id","title": {$first:"$title"},
"asin":{$first:"$asin"},
"categories": { $push: "$categories" }} },
{ $match: { "categories": { $in: ['T-Shirts']}} },
{ "$project":{ "_id": 0, "asin":1, "title":1 } } ])*
This is my current code for my index:
*var cursor =
db.products.explain("allPlansExecution").find(categories:{"T-Shirts"},{ categories:1, title:1, asin:1, _id:0,})
while (cursor.hasNext()) {
print(cursor.next());
}*
When I run the index code I should get nReturned as 8 currently at 0.
Could someone please guide me how to do this? Or can someone tell me what they would add?
There is not a simple way to index the individual values in an array contained inside another array.
It this case, since the values in question are string, you could use a text index, such as:
db.products.createIndex({"$**":"text"})
You could then use the $text query operator to search the index for an exact match:
db.products.find({$text:{$search:"\"T-Shirts\""}},{_id:0, asin:1, title:1})

mongodb - $sort child documents only

When i do a find all in a mongodb collection, i want to get maintenanceList sorted by older maintenanceDate to newest.
The sort of maintenanceDate should not affect parents order in a find all query
{
"_id":"507f191e810c19729de860ea",
"color":"black",
"brand":"brandy",
"prixVenteUnitaire":200.5,
"maintenanceList":[
{
"cost":100.40,
"maintenanceDate":"2017-02-07T00:00:00.000+0000"
},
{
"cost":4000.40,
"maintenanceDate":"2019-08-07T00:00:00.000+0000"
},
{
"cost":300.80,
"maintenanceDate":"2018-08-07T00:00:00.000+0000"
}
]
}
Any guess how to do that ?
Thank you
Whatever order the fields are in with the previous pipeline stage, as operations like $project and $group effectively "copy" same position.So, it will not change the order of your fields in your aggregated result.
And the sort of maintenanceDate through aggregation will not affect parents order in a find all query.
So, simply doing this should work.
Assuming my collection name is example.
db.example.aggregate([
{
"$unwind": "$maintenanceList"
},
{
"$sort": {
"_id": 1,
"maintenanceList.maintenanceDate": 1
}
},
{
"$group": {
"_id": "$_id",
"color": {
$first: "$color"
},
"brand": {
$first: "$brand"
},
"prixVenteUnitaire": {
$first: "$prixVenteUnitaire"
},
"maintenanceList": {
"$push": "$maintenanceList"
}
}
}
])
Output:

Mongodb aggregate, object sum inside object

I'm trying to agregate data in mongoDb.
This request perfectly works:
db.getCollection('map').aggregate([
{
$group: {
_id: "$Support",
gross: { $sum :"$Budget.Gross"},
}}
])
But, I'd prefere to have something like:
db.getCollection('map').aggregate([
{
$group: {
_id: "$Support",
Budget: { gross: { $sum :"$Budget.Gross"}},
}}
])
Which doesn't work, saying: "The field 'Budget' must me an accumulator object".
I understand why it is not possible to do it in that way. MongoDb doesn't know how to agregate { gross: { $sum :"$Budget.Gross"}}.
But, is there any way to obtain such a result ?
Thank you for your help
You have to use $projection to reshape the the output accordingly
db.getCollection('map').aggregate([
{ "$group": {
"_id": "$Support",
"gross": { "$sum": "$Budget.Gross" },
}},
{ "$project": {
"Budget": { "gross": "$gross" }
}}
])

How to set one data field to another date field in the same object of the collection mongodb

I am trying to edit the fields of entries in a collection. I am checking if the lastUpdated date is less then published date. If it is, then the entry is probably faulty and I need to make the lastUpdated date same as published date. I have created the following mongo query for it :-
db.runCommand({ aggregate: "collectionNameHere",pipeline: [
{
$project: {
isFaulty: {$lt: ["$lastUpdated","$published"]}
}
},{
$match: {
isFaulty: true
}
},{
$addFields: {
lastUpdated: "$published"
}
}]
})
I am able to get the list of documents which have this fault, but I am not able to update the field. The last $addFields does not seem to be working. There is no error as well. Can someone help me with this or if they can provide me a better query fro my use case.
Thanks a lot.
You're doing a mistake by trying to update with aggreggation, what is not possible. You have to use update command to achieve your goal.
Cannot test it right now, but this should do the job :
db.collection.update({
$expr: {
$lt: [
"$lastUpdated",
"$published"
]
}
},
{$set:{lastUpdated:"$published"}}
)
It is not possible to update the document with the same field. You can use $out aggregation
db.collection.aggregate([
{ "$match": { "$expr": { "$lt": ["$lastUpdated", "$published"] }}},
{ "$addFields": { "lastUpdated": "$published" }}
])
here but it always creates a new collection as the "output" which is also not a solution here.
So, at last You have to use some iteration here to first find the document using find query and then need to update it. And with the async await now it quite easy to work this type of nested asynchronous looping.
const data = await db.collection
.find({ "$expr": { "$lt": ["$lastUpdated", "$published"] }})
.project({ lastUpdated: 1 })
.toArray()
await Promise.all(data.map(async(d) => {
await db.collection.updateOne({ _id: d._id }, { $set: { lastUpdated: d.published }})
}))