skip to Main Content

In mongodb, is it possible to use $addToSet to test a certain object field for duplications, rather than the object as a whole?

For instance, when storing cookies found on a webpage, ie:

db.audits.insertOne( { _id: 1, cookies: [{name: "xx", value: "abc", ...}]})

can $push or $addToSet be used in a way whereby new objects are considered duplicates if they match the name field already present in the array? ie:

db.audits.updateOne(
   { _id: 1 },
   { $addToSet: { cookies: { $each: [ {name: "xx", value: "def"}, {name: "yy", value: "abc"} ] } } }
 )

desired result is for only {name: "yy",..} to be added to the array.

2

Answers


  1. One option is to use update with pipeline with $filter:

    db.audits.updateOne(
      { _id: 1 },
      [{
        $set: {cookies: {$concatArrays: [
              "$cookies",
              {$filter: {
                  input: [
                    {name: "xx", value: "def"},
                    {name: "yy", value: "abc"}
                  ],
                  cond: {$not: {$in: ["$$this.name", "$cookies.name"]}}
              }}
        ]}}
      }]
    )
    

    See how it works on the playground example

    Login or Signup to reply.
  2. Here is the working example with update aggregate :

    Data:

    [
      {
        _id: 1,
        cookies: [
          {
            name: "abc",
            value: "123"
          }
        ]
      },
      {
        _id: 2,
        cookies: [
          {
            name: "abc",
            value: "456"
          },
          {
            name: "some",
            value: "789"
          }
        ]
      },
      {
        _id: 3,
        cookies: []
      }
    ]
    

    Aggregate:

    db.collection.update({},
    [
      {
        $addFields: {
          "cookies": {
            $setUnion: [
              "$cookies",
              {
                $filter: {
                  input: [
                    {
                      name: "abc",
                      value: "def"
                    },
                    {
                      name: "yy",
                      value: "abc"
                    }
                  ],
                  cond: {
                    $not: {
                      $in: [
                        "$$this.name",
                        "$cookies.name"
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    ],
    {
      multi: true
    })
    

    Output:

    [
      {
        "_id": 1,
        "cookies": [
          {
            "name": "abc",
            "value": "123"
          },
          {
            "name": "yy",
            "value": "abc"
          }
        ]
      },
      {
        "_id": 2,
        "cookies": [
          {
            "name": "abc",
            "value": "456"
          },
          {
            "name": "some",
            "value": "789"
          },
          {
            "name": "yy",
            "value": "abc"
          }
        ]
      },
      {
        "_id": 3,
        "cookies": [
          {
            "name": "abc",
            "value": "def"
          },
          {
            "name": "yy",
            "value": "abc"
          }
        ]
      }
    ]
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search