0

I have a several documents with the following props:

{
  '_id':the_id
  'relationships': [{
      'rel_name': 'HAS_TAG'
      'rel_destination': 'TAG'
  },{
      'rel_name': 'HAS_CORE_TAG'
      'rel_destination': 'TAG'
  }]
}

Some documents have a larger list of relationships and those relationships always have a rel_name and a rel_destination. I'm banging my head to make a mongodb query so it can:

  1. find all documents that have at least one rel_name = HAS_CORE_TAG in relationships
  2. replace all rel_name = HAS_CORE_TAG to HAS_NEW_TAG

is that possible in one query? or should I iterate through all documents and the list relationships on each document?

Alvaro
  • 1,430
  • 2
  • 23
  • 41

2 Answers2

1

What you can do is, first get all documents which has at least "HAS_CORE_TAG" as you mentioned in the first senario. Then map each element and apply condition

{
    $match: {
        "relationships.rel_name": "HAS_CORE_TAG"
    }
}, {
    $addFields: {
        relationships: {
            $map: {
                input: '$relationships',
                as: "r",
                in: {
                    "rel_name": {
                        $cond: [{
                                $eq: ["$$r.rel_name", "HAS_CORE_TAG"]
                            },
                            "HAS_NEW_TAG", "$$r.rel_name"
                        ]

                    },
                    "rel_destination": "$$r.rel_destination"
                }
            }
        }
    }
}

Working Mongo playground

varman
  • 8,704
  • 5
  • 19
  • 53
1

You can use the filtered positional operator $[<identifier>] to do the magic.

Let's assume that the current collection looks like below:

{
  "relationships" : [
    {
      "rel_name": "HAS_TAG",
      "rel_destination": "TAG"
    },
    {
      "rel_name": "HAS_CORE_TAG",
      "rel_destination": "TAG"
    },
    {
      "rel_name": "HAS_CORE_TAG",
      "rel_destination": "TAG1"
    },
    {
      "rel_name": "HAS_CORE_TAG",
      "rel_destination": "TAG2"
    }
  ]
},
{
  "relationships" : [
    {
      "rel_name": "HAS_TAG",
      "rel_destination": "TAG"
    }
  ]
}

The below query will be helpful:

db.collection.update(
  {'relationships.rel_name': 'HAS_CORE_TAG'},
  {$set: {'relationships.$[elem].rel_name': 'HAS_NEW_TAG'}},
  {multi:true, arrayFilters: [
    {'elem.rel_name': 'HAS_CORE_TAG'}
  ]}
)

Now, the collection will be like below:

{
  "relationships" : [
    {
      "rel_name": "HAS_TAG",
      "rel_destination": "TAG"
    },
    {
      "rel_name": "HAS_NEW_TAG",
      "rel_destination": "TAG"
    },
    {
      "rel_name": "HAS_NEW_TAG",
      "rel_destination": "TAG1"
    },
    {
      "rel_name": "HAS_NEW_TAG",
      "rel_destination": "TAG2"
    }
  ]
},
{
  "relationships" : [
    {
      "rel_name": "HAS_TAG",
      "rel_destination": "TAG"
    }
  ]
}

You can read about it more here.

ngShravil.py
  • 4,742
  • 3
  • 18
  • 30