MongoDB - ArrayFilters [🔍]

We know that MongoDB is a schema-less, NoSql, document database which stores the documents in BSON format. This feature supports the flexible structure. A MongoDB document can have any number of embedded documents, nested arrays to it. 

Working with this kind of nested data models may sometimes be challenging when it comes for querying/updating.

The best part is that we have a concept called Array Filters in MQL, which helps in most ways to give us what we need from the collection of documents.

Now I will take you to look at how it works.

Let's say I have a MongoDB collection named - products.

Here is a sample document:

[{

  "_id": "1000435002",

  "name": "Toy-Tesseract",

  "onSale": true,

  "supplierId": "SP-NW-9760K",

  "category": {

    "catId": "Toy1001",

    "catName": "Hard Toy"

  },

  "stores": [

    {

      "live": true,

      "branchCode": "Xx-209-xX",

      "zip-code": 6743,

      "contractInitiated": [{

        "id": "MD324Xx209",

        "type": "Monthly",

        "on": "2021-01-14T08:04:59.850Z",

        "paid": true,

        "due": "2021-02-14T08:04:59.850Z"

      },

        {

        "id": "MD324Xx209",

        "type": "Monthly",

        "on": "2021-02-14T08:05:24.090Z",

        "paid": true,

        "due": "2021-03-14T08:05:24.090Z",

      },

        {

        "id": "MD324Xx209",

        "type": "Life-Time",

        "on": "2021-03-14T12:35:24.090Z",

        "paid": true,

        "due": "2022-03-14T12:35:24.090Z",

      }]

    },

    {

      "live": true,

      "branchCode": "Yx-135-xY",

      "zip-code": 345,

      "contractInitiated": [{

        "id": "TH004Yx135",

                   "type": "Monthly",

        "on": "2021-03-10T08:04:45.750Z",

        "paid": true,

        "due": "2021-04-10T08:04:45.750Z",

      },

        {

        "id": "MD324Xx209",

        "type": "Life-Time",

        "on": "2021-04-24T12:05:24.090Z",

        "paid": true,

        "due": "2022-04-24T12:05:24.090Z",

      }]

    },

    {

      "live": true,

      "branchCode": "TV-209-VT",

      "zip-code": 325,

      "contractInitiated": [{

        "id": "MD011TV325",

                   "type": "Monthly",

        "on": "2021-03-14T08:04:59.850Z",

        "paid": false,

        "due": "2021-04-14T08:04:59.850Z",

      }]

    },

    {

      "live": false,

      "branchCode": "Xx-156-xX",

      "zip-code": 116,

      "contractInitiated": [{

        "id": "MD022TV125",

                   "type": "Monthly",

        "on": "2021-01-28T08:04:59.850Z",

        "paid": true,

        "due": "2021-02-28T08:04:59.850Z",

      }]

    },

    {

      "live": false,

      "branchCode": "cdz-209",

      "zip-code": 7501,

      "contractInitiated": [{

        "id": "DR011TV125",

                   "type": "Monthly",

        "on": "2021-02-14T08:04:59.850Z",

        "paid": true,

        "due": "2021-03-14T08:04:59.850Z",

      }]

    }

  ],

  "productProperties": {

      "color": "Blue",

      "finish": "Glossy",

      "texture": "Hard",

      "origin": "Marvel",

      "description": "Tesseract Toy"

    },

  "productSheet": {

    "status": "Signed",

    "link": "xxxxx"

  },

  "designer": "xxjjiasuhg",

  "signedBy": "djfjss765d",

  "signedDate": "2021-01-01T08:25:07.960Z"

}]

Now, I want to update the contractInitiated->due date field to null value for contractInitiated->type "Life-Time".

The below query will do the magic.

Array Filter - Query:

db.products.update(
    {
        "stores.contractInitiated.type": "Life-Time"
    },
    {
        $set: {
            "stores.$[str].contractInitiated.$[ct].due": null
        }
    },
    {
        arrayFilters: [
            {
                "str.contractInitiated": {
                    $type: "array"
                }
            },
            {
                "ct.type": "Life-Time"
            }
        ],
        multi: true
    }

Query Explanation:

Here I have used filtered the documents form the collection products which has "stores.contractInitiated.type": "Life-Time"
Then I have used the array filter for update the "stores.contractInitiated.due":null for the condition satisfied documents.
The products collection has documents with embedded array of documents. The stores field is an object array which has another object array field called contractInitiated

Hence, in the arrayFilters -

"str.contractInitiated": {
                    $type: "array"
                }
is defined followed by the filter condition for the sub-doc array field type as below:
{
                "ct.type": "Life-Time"
}
multi: true - updates (multiple) all the documents that satisfies the filtered condition.




💁 Hope this blog will be helpful for the needful. For any queries post in the below comment section or reach out to me via the Contact Form from the home page.

💁 Subscribe for more interesting updates!

Comments