简体   繁体   中英

Sort MongoDB documents by specific content then by timestamp

I'm using nodejs with official mongodb's package. I got many documents in mongodb containing "type" and "timestamp" field. I want to sort it by prioritizing "type" (only specific content) and then "timestamp". As example I have following documents:

{ type: "book", timestamp: 1580825471 }
{ type: "house", timestamp: 1580825502 }
{ type: "water", timestamp: 1580825515 }
{ type: "book", timestamp: 1580825478 }
{ type: "smartphone", timestamp: 1580825522 }
{ type: "book", timestamp: 1580825424 }

My goal is to have sorted by that way to priority the type "book" first (and then sort it by timestamp)

{ type: "book", timestamp: 1580825478 }
{ type: "book", timestamp: 1580825471 }
{ type: "book", timestamp: 1580825424 }
{ type: "smartphone", timestamp: 1580825522 }
{ type: "water", timestamp: 1580825515 }
{ type: "house", timestamp: 1580825502 }

I was trying to use the db.collection.aggregate with following $sort value:

$sort: {
    type: "book",
    timestamp: -1
}

But that didn't worked out because the $sort field's value can only have the value of " 1 ", " -1 " or " { $meta: "textScore" } ".

Does anybody have an idea how to solve that issue?

Thanks in advance

EDIT:

This solution by using

$sort: {
  type: 1,
  timestamp: -1
}

is not a solution since then all types are also sorted which I don't want it. I just want to have "book" as first result then after that, types can be randomized (but timestamp is still being sorted.). Reason for that is that I want to list history entries (that's why I'm using timestamp to sort it), but I want to show type "book" at first. Even if the document are older than other documents. So yeah, for other types expect "book", I want it to be sorted by timestamp.

You can add an extra field in a project stage that creates a sort priority, then use that to sort on.

For example:

db.data.aggregate([
    { $addFields : { sortPriority: { $eq: [ "$type", "book" ] } } },
    { $sort: { sortPriority: -1, timestamp: -1} }
])

This will output the following:

{ "_id" : ObjectId("5e39892e0f18de54afe4d874"), "type" : "book", "timestamp" : 1580825478, "sortPriority" : true }
{ "_id" : ObjectId("5e39892e0f18de54afe4d871"), "type" : "book", "timestamp" : 1580825471, "sortPriority" : true }
{ "_id" : ObjectId("5e39892e0f18de54afe4d876"), "type" : "book", "timestamp" : 1580825424, "sortPriority" : true }
{ "_id" : ObjectId("5e39892e0f18de54afe4d875"), "type" : "smartphone", "timestamp" : 1580825522, "sortPriority" : false }
{ "_id" : ObjectId("5e39892e0f18de54afe4d873"), "type" : "water", "timestamp" : 1580825515, "sortPriority" : false }
{ "_id" : ObjectId("5e39892e0f18de54afe4d872"), "type" : "house", "timestamp" : 1580825502, "sortPriority" : false }

If you want to ommit the extra field add $unset stage:

db.data.aggregate([
    { $addFields : { sortPriority: { $eq: [ "$type", "book" ] } } },
    { $sort: { sortPriority: -1, timestamp: -1} },
    { $unset: "sortPriority" }
])

This will then output:

{ "_id" : ObjectId("5e39892e0f18de54afe4d874"), "type" : "book", "timestamp" : 1580825478 }
{ "_id" : ObjectId("5e39892e0f18de54afe4d871"), "type" : "book", "timestamp" : 1580825471 }
{ "_id" : ObjectId("5e39892e0f18de54afe4d876"), "type" : "book", "timestamp" : 1580825424 }
{ "_id" : ObjectId("5e39892e0f18de54afe4d875"), "type" : "smartphone", "timestamp" : 1580825522 }
{ "_id" : ObjectId("5e39892e0f18de54afe4d873"), "type" : "water", "timestamp" : 1580825515 }
{ "_id" : ObjectId("5e39892e0f18de54afe4d872"), "type" : "house", "timestamp" : 1580825502 }

You can create a sorting key by your own:

db.col.aggregate([
   {
      $addFields: {
         sortBy: {
            $cond: {
               if: { $eq: ["$type", "book"] }, then: 0, else: 1
            }
         }
      }
   },
   { $sort: { sortBy: 1, timestamp: 1 } },
   { $unset: "sortBy" }
])

Output:

{ "_id" : ObjectId("5e398952227b6d209de231bb"), "type" : "book", "timestamp" : 1580825424, "sortPriority" : true }
{ "_id" : ObjectId("5e398952227b6d209de231b6"), "type" : "book", "timestamp" : 1580825471, "sortPriority" : true }
{ "_id" : ObjectId("5e398952227b6d209de231b9"), "type" : "book", "timestamp" : 1580825478, "sortPriority" : true }
{ "_id" : ObjectId("5e398952227b6d209de231b7"), "type" : "house", "timestamp" : 1580825502, "sortPriority" : false }
{ "_id" : ObjectId("5e398952227b6d209de231b8"), "type" : "water", "timestamp" : 1580825515, "sortPriority" : false }
{ "_id" : ObjectId("5e398952227b6d209de231ba"), "type" : "smartphone", "timestamp" : 1580825522, "sortPriority" : false }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM