I'm trying to sort values after executing a find on my MongoDB by Java API. The result list contains the following entries:
{
"_id": "P17-223",
"property": "P17",
"itemid": 223,
"labels": [
  {
    "language": "en",
    "value": "Greenland"
  },
  {
    "language": "es",
    "value": "Groenlandia"
  },
  {
    "language": "de",
    "value": "Grönland"
  }
]
}
I want to sort by the first entry of the array labels:
  DBCursor cursor = getCollection().find(query);
  BasicDBObject orderBy = new BasicDBObject("labels[0].value", 1);
  cursor.sort(orderBy);
Cursor values are not sorted by this code. Can you help me?
Have you tried
BasicDBObject orderBy = new BasicDBObject("labels.0.value", 1);
It's not obvious, but the MongoDB documentation eludes to it. Using the $ sign matches the first item, but specifying the array element number seems to work. If anyone has a better document describing the behavior, please reply with the link.
From the documentation
Update Documents in an Array
The positional $ operator facilitates updates to arrays that contain embedded
documents. Use the positional $ operator to access the fields in the embedded
documents with the dot notation on the $ operator.
db.collection.update( { <query selector> }, { <update operator>: { "array.$.field" : value } } )
Documentation is here
I found this question/answer when looking for How to sort MongoDB (in Meteor) by first item of array…
I used this to find all documents in the Schedules collection which are active and then sort ascending by the first day in the days array.
Schedules.find(
  {
    active: true,
  },
  {
    sort: { 'days.0': 1 },
  },
)
A sample Schedule collection document with a Monday, Wednesday, Friday schedule looks something like this:
{
  _id: 9dh3ld0d7d0d,
  userId: UJD9dKd8edo,
  active: true,
  days: [1, 3, 5],
}
                        You cannot actually "sort" by a specific index of an array within a document in MongoDB. ct If you really must do this then you need the aggregation framework to "extract" the element to sort on.
I know the list form is actually deprecated, so this code is just for demonstration. Acutally define your pipeline as individual variables and feed those as argument to aggregate:
    BasicDBList pipeline = new BasicDBList();
    list.add(new BasicDBObject("$unwind","$labels"));
    list.add(new BasicDBObject("$group",
        new BasicDBObject("_id","$_id")
            .append("property", new BasicDBObject("$first","$property"))
            .append("itemid", new BasicDBObject("$first","$itemid"))
            .append("labels", new BasicDBObject("$push","$labels"))
            .append("maxLabel", new BasicDBObject("$max", "$labels.value"))
    ));
    list.add(new BasicDBObject("$sort", new BasicDBObject("maxLabel",1)));
    System.out.println(pipeline);
That gives you the serialized version which is the JSON form of:
db.collection.aggregate([ 
    { "$unwind" : "$labels" }, 
    { "$group": { 
        "_id": "$_id",
        "property": { "$first" : "$property" },
        "itemid": { "$first" : "$itemid" }, 
        "labels": { "$push" : "$labels" },
        "maxLabel": { "$max" : "$labels.value"}
    }}, 
    { "$sort" : { "maxLabel" : 1} }
])
Better applied in your code as:
collection.aggregate(unwind,group,sort);
Where those are individually declared.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With