bc110402922
bc110402922

Reputation: 457

How to match on the object level in MongoDB?

Input Documents

  "data": {
    "abc": {
      "Id": "100"

    },
    "xyz": {
      "Id": "123"
    }
}

Explanation : I want to do the $match on data.{i} i is parameter if I give to "abc" as a parameter I get the following output, I want to pass the multiple parameters to i "abc", "xyz".. How I can do that in do that $match the object key using parameter.

Expected Output :

  "data": {
    "abc": {
      "Id": "100"
    },
}

Upvotes: 1

Views: 482

Answers (2)

Dheemanth Bhat
Dheemanth Bhat

Reputation: 4452

Try this:

let keys = ["abc"];

db.collectionName.aggregate([
    {
        $project: {
            "filteredData": {
                $filter: {
                    input: { $objectToArray: "$data" },
                    as: "item",
                    cond: {
                        $in: ["$$item.k", keys]
                    }
                }
            }
        }
    },
    {
        $project: {
            data: { $arrayToObject: "$filteredData" }
        }
    }
]);

Output: When array keys = ["abc"];

{
    "_id" : ObjectId("60395e36e0c7d52970d3fa21"),
    "data" : {
        "abc" : {
            "Id" : "100"
        }
    }
}

Output: When array keys = ["abc", "xyz"];

{
    "_id" : ObjectId("60395e36e0c7d52970d3fa21"),
    "data" : {
        "abc" : {
            "Id" : "100"
        },
        "xyz" : {
            "Id" : "123"
        }
    }
}

Upvotes: 1

turivishal
turivishal

Reputation: 36104

  • Check the key is exists or not using $exists
  • project that key,
let i = "abc";
Schema.find(
  { ["data."+i]: { $exists: true } },
  { ["data."+i]: 1 }
)

Playground


Second option if you have list of keys in array,

  • map through prepare a query for $or condition, and prepare project part
let i = ["abc", "xyz"];
let query = [], project = {};
i.map(k => {
  query.push({ ["data."+k]: { $exists: true } });
  project["data."+k] = 1;
});

Schema.find({ $or: query }, project);

Playground


Third option using project operators starting from MongoDb v4.4, with more dynamic approach,

  • $objectToArray convert object to array
  • $filter to filter above converted array and get matching elements
  • $arrayToObject convert array back to object
let i = "abc";
Schema.find(
  { ["data."+i]: { $exists: true } },
  {
    data: {
      $arrayToObject: {
        $filter: {
          input: { $objectToArray: "$data" },
          cond: { $eq: ["$$this.k", i] }
        }
      }
    }
  }
)

Playground

Upvotes: 2

Related Questions