0

I have a two classes in Mongoengine that looks like that:

class User(Document):

user_id = StringField(required=True)
date_modified = DateTimeField(default=datetime.datetime.utcnow())
profile_link = URLField()
email = EmailField()
first_name = StringField()
last_name = StringField()
profile_image_metadata = EmbeddedDocumentListField(ImageMetadata)
meta = {'allow_inheritance': True,
        'index_background': True,
        'collection': 'users',
        'indexes': [{'fields': ['+user_id']}]
        }

class ImageMetadata(EmbeddedDocument):
"""
"""
img_url = URLField(unique=True)
img_content = BinaryField()
img_height = IntField(min_value=0)
img_width = IntField(min_value=0)
datetime = DateTimeField(datetime.datetime.utcnow())

So, I have the ImageMetadata class which is an Embedded document in an EmbeddedDocumentListField.

What I want to do is to get into the User's EmbeddedDocument list and delete for every ImageMetadata document the value of the img_content key.

So after the deletion, we will have all the metadata except those of the image_content

What I have tried is this:

User.objects(user_id=some_random_id).update_one(__raw__={
    '$pull': {'profile_image_metadata': {'img_content': {'$ne': None}}}})

But this deleted the whole ImageMetadata object from the list, not the img_content value.

Giorgos Perakis
  • 153
  • 2
  • 12
  • You want to remove the `img_content` key? as in `{ img_content: "somethingBinary", img_url: "somePath" }` to just `{ img_url: "somePath" }`? Abstracting there because I don't want to write the whole thing of course. You can do that with a `__raw__` argument, **however** MongoEngine itself will complain loudly because the model is different to that. So if you remove the field from the documents in the collection, the model needs to change as well. I think. It's been a while, but if memory serves it does not like it. Or do you mean something else? – Neil Lunn May 16 '18 at 09:35
  • I want to delete the value from the given key. Not the key itself. – Giorgos Perakis May 16 '18 at 10:15
  • Okay. You want `$set` with a positional `$` operator then. Another thing that never got fixed with mongoengine so still stick with the raw operation. Since it's in an array you need the "query" portion to match the array element you want to update. See [Update field in exact element array in MongoDB](https://stackoverflow.com/q/10432677/2313887). You'll want to `$set` to "empty" `BinaryContent`. You should have the helper from pymongo already in your code somewhere if you were setting content for that field before. – Neil Lunn May 16 '18 at 10:19
  • I used User.objects(user_id=some_random_id).update_one(__raw__={ '$set': {'profile_image_metadata': {'img_content': None}}}) and the result was to **delete every other key except** the img_content which had the value 'null'. So dropped everything except the key 'img_content' – Giorgos Perakis May 16 '18 at 10:43
  • 1
    You need to actually "read the link" you were given It shows how to update the matched element. The statement you just ran of course overwrites the array because that's what you are telling it to do. Read the link and follow it. The `$set` part will be more like `$set: { 'profile_image_metadata.$.image_content': None }` but you need to fix the **query**. Read the linked question. – Neil Lunn May 16 '18 at 10:51
  • I just did that. It worked. Thanks! – Giorgos Perakis May 16 '18 at 10:53
  • 1
    To make your model happy that probably really should be `BinData` with something empty rather than `None`. But the general point is updating the matched element. – Neil Lunn May 16 '18 at 10:54

0 Answers0