'How to project only the fields present in an array in MongoDB?

there is a document schema that has an array field called "updatedFields" which contains some fields names that you will find in "oldDocument" and "newDocument" objects. Here is its picture.

enter image description here

Now I want to project only those fields which exist in "updatedFields" array from "newDocument" and "oldDocument" like below:

 $project : { 
    "oldDocument.Modified":1,
    "oldDocument.Status":1,
    "newDocument.Modified":1,
    "newDocument.Status":1
 } 

Does anyone know how to build the project clause base on the fields' names in the array? I need a MongoDB query, not js code.



Solution 1:[1]

You can use $objectToArray in order to format the keys as values, $filter them according to the updatedFields array and then use $arrayToObject to make them keys again.

Edit: using $map inside the filter to cast dates to strings, according to a request on the comments.

Something like this:

db.collection.aggregate([
  {
    $project: {
      oldDocumentArr: {$objectToArray: "$oldDocument"},
      newDocumentArr: {$objectToArray: "$newDocument"},
      updatedFields: 1
    }
  },
  {
    $project: {
      oldDocumentFilter: {
        $map: {
          input: {
            $filter: {
              input: "$oldDocumentArr",
              as: "item",
              cond: {$in: ["$$item.k", "$updatedFields"]
              }
            }
          },
          "as": "obj",
          "in": {
            "k": "$$obj.k",
            "v": {$toString: "$$obj.v"}
          }
        }
      },
      newDocumentFilter: {
        $map: {
          input: {
            $filter: {
              input: "$newDocumentArr",
              as: "item",
              cond: {$in: ["$$item.k", "$updatedFields"]
              }
            }
          },
          "as": "obj",
          "in": {
            "k": "$$obj.k",
            "v": {$toString: "$$obj.v"}
          }
        }
      }
    }
  },
  {
    $project: {
      oldDocument: {$arrayToObject: "$oldDocumentFilter"},
      newDocument: {$arrayToObject: "$newDocumentFilter"},
      _id: 0
    }
  }
])

As you can see on the playground

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1