2
{
"_id" : ObjectId("5488303649f2012be0901e97"),
"user_id":3,
"my_shopping_list" : {
    "books" : [ ]
},
"my_library" : {
    "books" : [
        {
            "date_added" : ISODate("2014-12-10T12:03:04.062Z"),
            "tag_text" : [
                "english"
            ],
            "bdata_product_identifier" : "a1",
            "tag_id" : [
                "fa7ec571-4903-4aed-892a-011a8a411471"
            ]
        },
        {
            "date_added" : ISODate("2014-12-10T12:03:08.708Z"),
            "tag_text" : [
                "english",
                "hindi"
            ],
            "bdata_product_identifier" : "a2",
            "tag_id" : [
                "fa7ec571-4903-4aed-892a-011a8a411471",
                "60733993-6b54-420c-8bc6-e876c0e196d6"
            ]
        }
    ]
},
"my_wishlist" : {
    "books" : [ ]
},

}

Here I would like to remove only english from every tag_text array of my_library using only user_id and tag_text This document belongs to user_id:3. I have tried some queries which delete an entire book sub-document . Thank you.

Steve jobs
  • 43
  • 4
  • Have you looked at using [`$pull`](http://docs.mongodb.org/manual/reference/operator/update/pull/#up._S_pull)? – JohnnyHK Dec 10 '14 at 14:24
  • @JohnnyHK Yes. But the syntax I used was wrong. Query was deleting entire sub document that contains the tag_text – Steve jobs Dec 11 '14 at 04:42

2 Answers2

1

One possible solution could be to repeat

db.collection.update({user_id: 3, "my_library.books.tag_text": "english"}, {$pull: {"my_library.books.$.tag_text": "english"}}

until MongoDB can no longer match a document to update.

user200015
  • 27
  • 3
  • Thanku for the answer. It's partially correct. It removes `english` from `tag_text` array only from first sub-document(here only of "a1" bdata_product identifier). – Steve jobs Dec 11 '14 at 05:04
1

Well since you are using pymongo and mongodb doesn't provide a nice way for doing this because using the $ operator will only pull english from the first subdocument, why not write a script that will remove english from every tag_text and then update your document.

Demo:

>>> doc = yourcollection.find_one(
    {
        'user_id': 3, "my_library.books" : {"$exists": True}},
        {"_id" : 0, 'user_id': 0
    })

>>> books = doc['my_library']['books'] #books field in your doc
>>> new_books = []

>>> for k in books:
...     for x, y in k.items():
...         if x == 'tag_text' and 'english' in y:
...             y.remove('english')
...         new_book.append({x:y})
... 
>>> new_book
[{'tag_text': []}, {'tag_id': ['fa7ec571-4903-4aed-892a-011a8a411471']},   {'bdata_product_identifier': 'a1'}, {'date_added': datetime.datetime(2014, 12, 10, 12, 3, 4, 62000)}, {'tag_text': ['hindi']}, {'tag_id': ['fa7ec571-4903-4aed-892a-011a8a411471', '60733993-6b54-420c-8bc6-e876c0e196d6']}, {'bdata_product_identifier': 'a2'}, {'date_added': datetime.datetime(2014, 12, 10, 12, 3, 8, 708000)}]

>>> yourcollection.update({'user_id' : 3}, {"$set" : {'my_library.books' : bk}})

Check if everything work fine.

>>> yourcollection.find_one({'user_id' : 3})
{'user_id': 3.0, '_id': ObjectId('5488303649f2012be0901e97'), 'my_library': {'books': [{'tag_text': []}, {'tag_id': ['fa7ec571-4903-4aed-892a-011a8a411471']}, {'bdata_product_identifier': 'a1'}, {'date_added': datetime.datetime(2014, 12, 10, 12, 3, 4, 62000)}, {'tag_text': ['hindi']}, {'tag_id': ['fa7ec571-4903-4aed-892a-011a8a411471', '60733993-6b54-420c-8bc6-e876c0e196d6']}, {'bdata_product_identifier': 'a2'}, {'date_added': datetime.datetime(2014, 12, 10, 12, 3, 8, 708000)}]}, 'my_shopping_list': {'books': []}, 'my_wishlist': {'books': []}}
styvane
  • 59,869
  • 19
  • 150
  • 156