2

I have mongo documents with the following structure:

{
    name: 'AKL to DUD Via CHC',
    rates: [
        {
            container_id: 'abc',
            buyRate: 380
        },
        {
            container_id: 'def',
            buyRate: 410
        }
    ]
}
{
    name: 'AKL to DUD',
    rates: [
        {
            container_id: 'abc',
            buyRate: 400
        },
        {
            container_id: 'def',
            buyRate: 420
        }
    ]
}

I would like to have a sort in my aggregation pipeline based on the buyRate of a specific container_id, e.g. if I passed in a container_id of abc I would like to sort on the buyRate of just abc so that (in this case) the second document is returned first.

I can get it working by adding in a field with rates filtered by the container_id and then sorting on that but it seems overly complex:

db.services.aggregate([
    { $addFields: { "containerBuyRate":
            { $filter: {
                input: "$rates",
                as: "rate",
                cond: { $eq: [ "$$rate.container_id", "abc") ] }
            }}
     }},
     { $sort: {'containerBuyRate.buyRate': -1}}
])

Is there a more concise way to achieve this?

2 Answers 2

3

Your approach is fine.

Another way:

Difference is $addFields will add one more field as an object.

Working example.

db.getCollection('Example').aggregate([
  { $addFields: {
    containerBuyRate: {$arrayElemAt: [ "$rates", { $indexOfArray: [ "$rates.container_id", "abc" ] } ] }}
  },
  { $sort: {'containerBuyRate.buyRate': -1}}
])

Output:

[
  {
    "_id": ObjectId("5a934e000102030405000002"),
    "containerBuyRate": {
      "buyRate": 405,
      "container_id": "abc"
    },
    "name": "AKL to DUD Via CHC",
    "rates": [
      {
        "buyRate": 405,
        "container_id": "abc"
      },
      {
        "buyRate": 500,
        "container_id": "def"
      }
    ]
  },
  {
    "_id": ObjectId("5a934e000102030405000001"),
    "containerBuyRate": {
      "buyRate": 400,
      "container_id": "abc"
    },
    "name": "AKL to DUD",
    "rates": [
      {
        "buyRate": 400,
        "container_id": "abc"
      },
      {
        "buyRate": 420,
        "container_id": "def"
      }
    ]
  },
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "containerBuyRate": {
      "buyRate": 380,
      "container_id": "abc"
    },
    "name": "AKL to DUD Via CHC",
    "rates": [
      {
        "buyRate": 380,
        "container_id": "abc"
      },
      {
        "buyRate": 410,
        "container_id": "def"
      }
    ]
  },
  {
    "_id": ObjectId("5a934e000102030405000003"),
    "containerBuyRate": {
      "buyRate": 300,
      "container_id": "abc"
    },
    "name": "AKL to DUD Via CHC",
    "rates": [
      {
        "buyRate": 300,
        "container_id": "abc"
      },
      {
        "buyRate": 700,
        "container_id": "def"
      }
    ]
  },
  {
    "_id": ObjectId("5a934e000102030405000004"),
    "containerBuyRate": {
      "buyRate": 100,
      "container_id": "abc"
    },
    "name": "AKL to DUD Via CHC",
    "rates": [
      {
        "buyRate": 1000,
        "container_id": "def"
      },
      {
        "buyRate": 100,
        "container_id": "abc"
      }
    ]
  }
]

Thank you @Alex to point out my mistake on the last solution.

Sign up to request clarification or add additional context in comments.

6 Comments

It's completely wrong. First of all if you run your aggregation on the OPs data you get 2 documents, not 3: mongoplayground.net/p/FJsbD84cCwA Secondly, you change order of elements in the array which may have side effects. Most importantly $sort doesn't sort by first element but by element with max value. Here mongoplayground.net/p/OjtWJd1OgqG I only changed {container_id: "def", buyRate: 410} to {container_id: "def", buyRate: 510} and it changed order of documents in the output.
@AlexBlex 1) I have tried with one more documents. So the result is in 3 documents. 2) $sort doesn't sort by the first element but by element with max value. Could you please give me any link so I can refer this sentence, maybe I am confused here. 3) You changed value buyrate to 510 and it changed the order of document which is correct as per OP's requirement. Thank you!
I changed buyRate for subdoc with container_id: "def". It should not change order if we sort by buyRate of subdocs with container_id: "abc", right?
@AlexBlex, Thank you to point me in the right direction. I had completely missed out negative scenario.
That's much better. Sorry I couldn't find a link to the docs about sorting. I guess it's the case where stackoverflow fills the gaps in the documentation.
|
1

For sorting containerBuyRate array you need to unwind it and sort it

db.services.aggregate([
     { $addFields: { "containerBuyRate":
        { $filter: {
            input: "$rates",
            as: "rate",
            cond: { $eq: [ "$$rate.container_id", "abc" ] }
        }}
     }},
     { $unwind: "$containerBuyRate" },
     { $sort: {"containerBuyRate.buyRate": -1}},
     { $group: { 
         _id: "$_id",
         containerBuyRate: {$push: "$containerBuyRate"},
         name: { $first: "$name"},
         rates: {$first: "$rates"} 
     }}
])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.