skip to Main Content

I have this:

  • A field which is a map where the keys are UUIDs and the value another object which is not relevant.
  • A list of UUIDs that should be passed as parameter.

I want to:

delete from the collection all documents where all keys of the map are included in the list of UUIDs

The object:

@Document
public class MyClass
{
  private Map<UUID, anotherObject> myMap;
}

With derived queries I am not able to reach the UUID because has no name -> deleteByMyMap…

And with a query I know that there is a way to convert the map into an array ($expr and $objectToArray) but I do not know if it makes sense.

  • Is there any way to do this?
  • How can I access just the key of the map?

3

Answers


  1. Chosen as BEST ANSWER

    This could be also an answer:

    db.collection.aggregate([
      {
        "$project": {
          "mapAsArray": {
            "$objectToArray": "$map"
          }
        }
      },
      {
        "$match": {
          "mapAsArray": {
            "$not": {
              "$elemMatch": {
                "k": {
                  $nin: [
                    "3478956c-3a01-404f-84e7-2a076e165215",
                    "1e1d1efb-5bf9-48ac-93ca-4a2df5a9f7eb"
                  ]
                }
              }
            }
          }
        }
      }
    ])
    

    Here the mongoplayground

    The map to spring-data-mongodb:

    ProjectionOperation projectionOperation = project()
                .and(ObjectOperators.valueOf(myMap).toArray()).as(myMapToArray);
    
    MatchOperation matchOperation = match(where(myMapToArray)
                .not()
                .elemMatch(where("k").nin(myList)));
    
    AggregationResults<myObject> aggregate = mongoTemplate.aggregate(newAggregation(projectionOperation, matchOperation),
                myObject.class, myObject.class);
    

  2. try this it might help:
    Get keys in a single document
    You can also use aggregation to get keys in a single document:

    db.activities.aggregate([ {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}}, {"$project":{"keys":"$arrayofkeyvalue.k"}} ])
    

    to delete:

    db['name1.name2.name3.Properties'].remove([ { "key" : "name_key1" }, { "key" : "name_key2" }, { "key" : "name_key3" } )]
    
    Login or Signup to reply.
  3. This is one way of doing it, use an aggregation pipeline to get _id of all documents matching your criteria:

    db.collection.aggregate([
      {
        "$addFields": {
          keysOfMap: {
            "$map": {
              "input": {
                "$objectToArray": "$myMap"
              },
              "as": "item",
              "in": "$$item.k"
            }
          },
          
        }
      },
      {
        "$addFields": {
          "difference": {
            "$setDifference": [
              "$keysOfMap",
              [
                "63f62530-89b1-439e-bcb3-2c7ab614ecda",
                "dcbb1469-3ca0-4547-b7d1-296ba2f0a01d"
              ]
            ]
          }
        }
      },
      {
        "$match": {
          difference: []
        }
      },
      {
        "$project": {
          _id: 1
        }
      }
    ])
    

    How it works:

    1. At first, the map the converted into an array, and then that array is mapped to the keys.
    2. Then the difference, between the keys array and the list of ids is calculated.
    3. Then all documents having empty differences are picked up and their _id is projected.

    Using these ids, you can simply do:

    db.collection.remove({_id: {$in: [// the list here]}});
    

    Playground for the aggregation.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search