Vishal Kumar
Vishal Kumar

Reputation: 69

How to query on embedded documents

{
    "_id" : ObjectId("5fa919a49bbe481d117506c9"),
    "isDeleted" : 0,
    "productId" : 31,
    "references" : [ 
        {
            "_id" : ObjectId("5fa919a49bbe481d117506ca"),
            "languageCode" : "en",
            "languageId" : 1,
            "productId" : ObjectId("5fa919a49bbe481d117506ba")
        }, 
        {
            "_id" : ObjectId("5fa91cc7d7d52f1e389dee1f"),
            "languageCode" : "ar",
            "languageId" : 2,
            "productId" : ObjectId("5fa91cc7d7d52f1e389dee1e")
        }
    ],
    "createdAt" : ISODate("2020-11-09T10:27:48.859Z"),
    "updatedAt" : ISODate("2020-11-09T10:27:48.859Z"),
    "__v" : 0
},

{
    "_id" : ObjectId("5f9aab1d8e475489270ebe3a"),
    "isDeleted" : 0,
    "productId" : 21,
    "references" : [ 
        {
            "_id" : ObjectId("5f9aab1d8e475489270ebe3b"),
            "languageCode" : "en",
            "languageId" : 1,
            "productId" : ObjectId("5f9aab1c8e475489270ebe2d")
        }
    ],
    "createdAt" : ISODate("2020-10-29T11:44:29.852Z"),
    "updatedAt" : ISODate("2020-10-29T11:44:29.852Z"),
    "__v" : 0
}

This is my mongoDB collection in which i store the multilingual references to product collection. In productId are the references to product Collection. Now If we have ar in our request, then we will only have the productId of ar languageCode. If that languageCode does not exist then we will have en langCode productId.

For Example if the user pass ar then the query should return

 "productId" : ObjectId("5fa91cc7d7d52f1e389dee1e")
 "productId" : ObjectId("5f9aab1c8e475489270ebe2d")

I have tried using $or with $elemMatch but I am not able to get the desired result. Also i am thinking of using $cond. can anyone help me construct the query.

Upvotes: 1

Views: 91

Answers (2)

varman
varman

Reputation: 8894

We can acheive

  • $facet helps to categorized the incoming documents
  • In the arArray, we get all documents which has"references.languageCode": "ar" (This document may or may not have en), then de-structure the references array, then selecting the "references.languageCode": "ar" only using $match. $group helps to get all productIds which belong to "references.languageCode": "ar"
  • In the enArray, we only get documents which have only "references.languageCode": "en". Others are same like arArray.
  • $concatArrays helps to concept both arArray,enArray arrays
  • $unwind helps to de-structure the array.
  • $replaceRoot helps to make the Object goes to root

Here is the mongo script.

db.collection.aggregate([
  {
    $facet: {
      arAarray: [
        {
          $match: {
            "references.languageCode": "ar"
          }
        },
        {
          $unwind: "$references"
        },
        {
          $match: {
            "references.languageCode": "ar"
          }
        },
        {
          $group: {
            _id: "$_id",
            productId: {
              $addToSet: "$references.productId"
            }
          }
        }
      ],
      enArray: [
        {
          $match: {
            $and: [
              {
                "references.languageCode": "en"
              },
              {
                "references.languageCode": {
                  $ne: "ar"
                }
              }
            ]
          }
        },
        {
          $unwind: "$references"
        },
        {
          $group: {
            _id: "$_id",
            productId: {
              $addToSet: "$references.productId"
            }
          }
        }
      ]
    }
  },
  {
    $project: {
      combined: {
        "$concatArrays": [
          "$arAarray",
          "$enArray"
        ]
      }
    }
  },
  {
    $unwind: "$combined"
  },
  {
    "$replaceRoot": {
      "newRoot": "$combined"
    }
  }
])

Working Mongo playground

Upvotes: 1

JuniorBasilio
JuniorBasilio

Reputation: 31

You can test this solution to see if it is useful for you question:

db.collection.aggregate([
    {
        $addFields: {
            foundResults:
            {
                $cond: {
                    if: { $in: ["ar", "$references.languageCode"] }, then:
                    {
                        $filter: {
                            input: "$references",
                            as: "item",
                            cond: {
                                $and: [{ $eq: ["$$item.languageCode", 'ar'] },
                                ]
                            }
                        }
                    }

                    , else:
                    {
                        $filter: {
                            input: "$references",
                            as: "item",
                            cond: {
                                $and: [{ $eq: ["$$item.languageCode", 'en'] },
                                ]
                            }
                        }
                    }
                }
            }
        }
    },
    { $unwind: "$foundResults" },
    { $replaceRoot: { newRoot: { $mergeObjects: ["$foundResults"] } } },
    { $project: { _id: 0, "productId": 1 } }
])

Upvotes: 0

Related Questions