mongodbmongodb-queryaggregation

Looking for help to aggregating user orders data


I have an aggregation use case where I have a large JSON containing product orders data that I need to aggregate.

Below is a small subset of the data which I am planning to aggregate and seek your assistance.

[
  {
    "orderid": "1111",
    "order_type": "individual",
    "users": [
      {
        "name": "user1",
        "phone": 982928,
        "items": [
          {
            "name": "AAA",
            "qty": 20,
            "price": 10
          },
          {
            "name": "BBB",
            "qty": 30,
            "price": 15
          }
        ]
      },
      {
        "name": "user2",
        "phone": 948783,
        "items": [
          {
            "name": "AAA",
            "qty": 10,
            "price": 10
          },
          {
            "name": "CCC",
            "qty": 5,
            "price": 20
          }
        ]
      },
      {
        "name": "user3",
        "phone": 787868,
        "items": [
          {
            "name": "BBB",
            "qty": 40,
            "price": 10
          },
          {
            "name": "CCC",
            "qty": 15,
            "price": 20
          }
        ]
      }
    ]
  },
  {
    "orderid": "2222",
    "order_type": "bulk",
    "users": [
      {
        "name": "user1",
        "phone": 982928
      },
      {
        "name": "user3",
        "phone": 787868
      }
    ],
    "items": [
      {
        "name": "AAA",
        "qty": 3,
        "price": 10
      },
      {
        "name": "BBB",
        "qty": 15,
        "price": 10
      }
    ]
  }
]

A bit of explanation about the structure of the JSON structure.

The JSON array contains a mix of JSON objects with a differentiator being order_type field as a deciding factor of how the orders are structured.

  1. When order_type = "individual", the orders are structured in the users array where each array element is a user object that contains user information such as name and phone number along with an items that contains the orders placed by the user.
  2. When order_type = "bulk", users and orders are structured little differently where two separate arrays are maintained. The array users contains information about user(s) and items array containing orders placed by each users in the users array.

The output I am looking to achieve would look something like:

[
  {
    "user":"user1",
    "orders":[1111,2222],
    "unique_items":2
  },
  {
    "user":"user2",
    "orders":[1111],
    "unique_items":2
  },
  {
    "user":"user3",
    "orders":[1111,2222],
    "unique_items":3
  }
]

A logical view(from my viewpoint) of how the data is to be aggregated in a pipeline, the aggregation should begin by selecting all distinct users appearing in all the array elements and proceed with combining orderid(s) that contains orders where each user is present and then proceed with calculating number of unique product/item name(s) appearing in each of the order for that user. This way the algorithm should proceed with and output the resultant JSON structure above.

I am relatively new at aggregation, any help in this regard would be highly appreciated.


Solution

  • Could be this one:

    db.collection.aggregate([
      {
        $set: {
          items: "$$REMOVE",
          users: {
            $map: {
              input: "$users",
              in: { $mergeObjects: [ "$$this", { items: "$items" } ] }
            }
          }
        }
      },
      { $unwind: "$users" },
      {
        $group: {
          _id: "$users.name",
          orders: { $addToSet: "$orderid" },
          unique_items: { $addToSet: "$users.items.name" }
        }
      },
      {
        $set: {
          items: {
            $reduce: {
              input: "$unique_items",
              initialValue: [],
              in: { $concatArrays: [ "$$value", "$$this" ] }
            }
          }
        }
      },
      {
        $set: {
          items: "$$REMOVE",
          unique_items: { $size: { $setUnion: "$items" } }
        }
      }
    ])
    

    Mongo Playground