Sort collection in mongodb based on property in Array - mongodb

{
'name':'abc',
'records': {
'entries':[
{
'date_created':'2020-01-01T00:00:00',
'some_filed':'value'
},
{
'date_created':'2019-02-03T05:00:00',
'some_filed':'value'
}
]
}
},
{
'name':'xyz',
'records': {
'entries':[
{
'date_created':'2022-03-07T08:00:00',
'some_filed':'value'
},
{
'date_created':'2022-02-08T10:987:00',
'some_filed':'value'
}
]
}
}
I have above collection format. I want to sort this based on date_created from first record in the array , i.e I want to perform sorting based on records.entries[0].date_created.
Also I need to project the name and records.entries[0].date_created fields.
I tried below queries
db['sample_collection'].find({}, {'records.entries.0.date_created':1, 'name':1})

db.collection.aggregate([
{
$set: { firstObject: { $first: "$records.entries.date_created" } }
},
{
$sort: { firstObject: -1 }
}
])
mongoplayground

Related

MongoDB sorting does not work with inner array

I'm trying to query specific fields in my document and sort them by one of the fields, however, the engine seems to completely ignore the sort.
I use the query:
db.symbols.find({_id:'AAPL'}, {'income_statement.annual.totalRevenue':1,'income_statement.annual.fiscalDateEnding':1}).sort({'income_statement.annual.totalRevenue': 1})
This is the output:
[
{
_id: 'AAPL',
income_statement: {
annual: [
{
fiscalDateEnding: '2021-09-30',
totalRevenue: '363172000000'
},
{
fiscalDateEnding: '2020-09-30',
totalRevenue: '271642000000'
},
{
fiscalDateEnding: '2019-09-30',
totalRevenue: '256598000000'
},
{
fiscalDateEnding: '2018-09-30',
totalRevenue: '265595000000'
},
{
fiscalDateEnding: '2017-09-30',
totalRevenue: '229234000000'
}
]
}
}
]
I would expect to have the entries sorted by fiscalDateEnding, starting with 2017-09-30 ascending.
However, the order is fixed, even if I use -1 for sorting.
Any ideas?
The sort you are using is for the ordering of documents in the result set. This is different from the ordering of array elements inside the document.
For your case, if you are using a newer version of MongoDB (5.2+), you can use the $sortArray.
db.symbols.aggregate([
{
$project: {
_id: 1,
annual: {
$sortArray: {
input: "$income_statement.annual",
sortBy: {
fiscalDateEnding: 1
}
}
}
}
}
])
If you are using older version of MongoDB, you can do the followings to perform the sorting.
db.collection.aggregate([
{
"$unwind": "$income_statement.annual"
},
{
$sort: {
"income_statement.annual.fiscalDateEnding": 1
}
},
{
$group: {
_id: "$_id",
annual: {
$push: "$income_statement.annual"
}
}
},
{
"$project": {
_id: 1,
income_statement: {
annual: "$annual"
}
}
}
])
Here is the Mongo Playground for your reference.

Delete document that has size greater than a specific value

I have a collection which contains a multiple documents whose size has increased from 16MBs or is about to reach 16MBs.
I want query that finds documents which have size greater than 10MBs and delete all of them.
I am using following to find the size of document.
Object.bsonsize(db.test.findOne({type:"auto"}))
Is there a way to embed this query inside db.test.deleteMany() query?
This following query deletes the documents with size greater than the specified size (the size is specified in bytes). This query is valid with MongoDB v4.4 or higher.
db.collection.deleteMany( {
$expr: { $gt: [ { $bsonSize: "$$ROOT" }, SIZE_LIMIT ] },
type: "auto"
} )
The following script runs for MongoDB v4.2 or earlier:
const SIZE_LIMIT = 75 // substitute your value here in bytes
let idsToDelete = [ ]
let crsr = db.collection.find()
while(crsr.hasNext()) {
let doc= crsr.next()
if (Object.bsonsize(doc) > SIZE_LIMIT) {
idsToDelete.push(doc._id)
}
}
db.collection.deleteMany( { _id: { $in: idsToDelete } } )
I think you have to do it like this:
db.test.aggregate([
{ $match: { type: "auto" } },
{ $project: { bsonSize: { $bsonSize: "$$ROOT" } } },
{ $match: { bsonSize: { $gt: 16e6 } } },
]).forEach(function (doc) {
db.test.deleteOne({ _id: doc._id });
})
Or if you prefer deleteMany:
var ids = db.test.aggregate([
{ $match: { type: "auto" } },
{ $project: { bsonSize: { $bsonSize: "$$ROOT" } } },
{ $match: { bsonSize: { $lt: 16e6 } } }
]).toArray().map(x => x._id);
db.test.deleteMany({ _id: { $in: ids } });

return only the last level of the embedded property that is searched in a document

I have these documents.
db.test.find({"house.floor":1})
db.test.insertMany([{
"name":"homer",
"house": {
"floor": 1,
"room":
{
"bed": "bed_pink",
"chair":"chair_pink"
}
}
},
{
"name":"marge",
"house": {
"floor": 1,
"room":
{
"bed": "bed_blue",
"chair":"chair_red"
}
}
}]
)
db.test.find({"house.room.bed":"bed_blue"})
I want to return only the value of the last level of my search. in this case:
{
"bed": "bed_blue",
"chair":"chair_red"
}
the answer I get, is the whole document, I want to advance to a certain level of the query. how can I do it?
You can use aggregation for it
db.test.aggregate([
{ $match: { "house.room.bed":"bed_blue" } },
{ $replaceRoot: { newRoot: "$house.room" } }
])
You can use aggregate together with $match and $project for this as follows:
db.test.aggregate([
{
$match: {
"house.room.bed": "bed_blue"
}
},
{
$project: {
"_id": 0,
"bed": "$house.room.bed",
"chair": "$house.room.chair"
}
}
])
Further, you can modify the $project part as needed.
Here is a demo: https://mongoplayground.net/p/Fvll0LFIvQy

Updating array of sub sub document with matching element

Below is my schema:
{
"_id":ObjectId("5c49c783de72ec2ec47b95d1"),
"placement":[
{
"offer":[
{
"sent_by":"John",
"comment":""
},
{
"sent_by":"Mary",
"comment":""
}
]
}
]
}
I want to update placement.offer.comment where placement.offer.sent_by is Mary but it always updates the first record. I don't want to provide a hard coded number like placement.0.offer.1.sent_by.
This should be the resulting document:
{
"_id":ObjectId("5c49c783de72ec2ec47b95d1"),
"placement":[
{
"offer":[
{
"sent_by":"John",
"comment":""
},
{
"sent_by":"Mary",
"comment":"Some comment updated"
}
]
}
]
}
You would need to use array filters to achieve that:
db.collection.update(
{ /* add additional query filters here */ },
{ $set: { "placement.$[].offer.$[o].comment": "Some updated comment" } },
{ arrayFilters: [ { "o.sent_by": "Mary" } ] }
)

How to find several items from the same array in Mongodb?

In the collection "friendship" I would like to find all Bart's friends that are 10. The $elemMatch query only returns the first matching element of the array : I only get Milhouse. How can I get Milhouse and Martin ?
{ name:'Bart',
age:10
friends:[
{ name:'Milhouse',
age:10
},
{ name:'Nelson',
age:11
},
{ name:'Martin',
age:10
}
]
},
{ name:'Lisa',
age:8
friends:[
...
]
}
Try to use aggregation framework for this task (especially $unwind operator):
db.friendship.aggregate([
{ $match: { name: "Bart" } },
{ $unwind: "$friends" },
{ $match: { "friends.age": 10 } }
]);