0

I've two orders and these orders have multiple shipments and shipments have multiple products. How can I sort the orders based on the minimum product.quantity in a shipment?

For example. When ordering ascending, orderNo = 2 should be listed first because it has a shipment that contains a product.quantity=1. (This is the minimum value among all product.quantity values. (productName doesn't matter)

{
  "orders": [
    {
      "orderNo": "1",
      "shipments": [
        {
          "products": [
            {
              "productName": "AAA",
              "quantity": "2"
            },
            {
              "productName": "AAA",
              "quantity": "2"
            }
          ]
        },
        {
          "products": [
            {
              "productName": "AAA",
              "quantity": "3"
            },
            {
              "productName": "AAA",
              "quantity": "6"
            }
          ]
        }
      ]
    },
    {
      "orderNo": "2",
      "shipments": [
        {
          "products": [
            {
              "productName": "AAA",
              "quantity": "1"
            },
            {
              "productName": "AAA",
              "quantity": "6"
            }
          ]
        },
        {
          "products": [
            {
              "productName": "AAA",
              "quantity": "4"
            },
            {
              "productName": "AAA",
              "quantity": "5"
            }
          ]
        }
      ]
    }
  ]
}

1 Answer 1

1

Assuming that each order is a separate document, you could create an order-focused index where both shipments and products are nested fields to prevent array flattening.

The minimal index mapping could then look like:

PUT orders
{
  "mappings": {
    "properties": {
      "shipments": {
        "type": "nested",
        "properties": {
          "products": {
            "type": "nested"
          }
        }
      }
    }
  }
}

The next step is to ensure the quantity is always numeric -- not a string. When that's done, insert said docs:

POST orders/_doc
{"orderNo":"1","shipments":[{"products":[{"productName":"AAA","quantity":2},{"productName":"AAA","quantity":2}]},{"products":[{"productName":"AAA","quantity":3},{"productName":"AAA","quantity":6}]}]}

POST orders/_doc
{"orderNo":"2","shipments":[{"products":[{"productName":"AAA","quantity":1},{"productName":"AAA","quantity":6}]},{"products":[{"productName":"AAA","quantity":4},{"productName":"AAA","quantity":5}]}]}

Finally, you can use nested sorting:

POST orders/_search
{
  "sort": [
    {
      "shipments.products.quantity": {
        "nested": {
          "path": "shipments.products"
        },
        "order": "asc"
      }
    }
  ]
}

Tip: To make the query even more useful, you could introduce sorted inner_hits to not only sort the top-level orders but also the individual products enclosed in a given order. These inner hits need a nested query so you could simply add a non-negative condition on shipments.products.quantity.

When you combine this query with the above sort and restrict the response to only relevant attributes with filter_path:

POST orders/_search?filter_path=hits.hits._id,hits.hits._source.orderNo,hits.hits.inner_hits.*.hits.hits._source
{
  "_source": ["orderNo", "non_negative_quantities"], 
  "query": {
    "nested": {
      "path": "shipments.products",
      "inner_hits": {
        "name": "non_negative_quantities",
        "sort": {
          "shipments.products.quantity": "asc"
        }
      },
      "query": {
        "range": {
          "shipments.products.quantity": {
            "gte": 0
          }
        }
      }
    }
  },
  "sort": [
    {
      "shipments.products.quantity": {
        "nested": {
          "path": "shipments.products"
        },
        "order": "asc"
      }
    }
  ]
}

you'll end up with both sorted orders AND sorted products:

{
  "hits" : {
    "hits" : [
      {
        "_id" : "gVc0BHgBly0XYOUcZ4vd",
        "_source" : {
          "orderNo" : "2"                   <---
        },
        "inner_hits" : {
          "non_negative_quantities" : {
            "hits" : {
              "hits" : [
                {
                  "_source" : {
                    "quantity" : 1,         <---
                    "productName" : "AAA"
                  }
                },
                {
                  "_source" : {
                    "quantity" : 4,         <---
                    "productName" : "AAA"
                  }
                },
                {
                  "_source" : {
                    "quantity" : 5,         <---
                    "productName" : "AAA"
                  }
                }
              ]
            }
          }
        }
      },
      {
        "_id" : "gFc0BHgBly0XYOUcYosz",
        "_source" : {
          "orderNo" : "1"
        },
        "inner_hits" : {
          "non_negative_quantities" : {
            "hits" : {
              "hits" : [
                {
                  "_source" : {
                    "quantity" : 2,
                    "productName" : "AAA"
                  }
                },
                {
                  "_source" : {
                    "quantity" : 2,
                    "productName" : "AAA"
                  }
                },
                {
                  "_source" : {
                    "quantity" : 3,
                    "productName" : "AAA"
                  }
                }
              ]
            }
          }
        }
      }
    ]
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the detailed explanation, it worked!
Cool! hey if it helped, upvote and accept the answer.

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.