0

I have this models:

class Sub(EmbeddedDocument):
    name = StringField()

class Main(Document):
    subs = ListField(EmbeddedDocumentField(Sub))

When i use this query, it returns all of Main data but i just need subs that their name is 'foo'.

query: Main.objects(__raw__={'subs': {'$elemMatch': {'name': 'foo'}}})

For example with this data:

{
  subs: [
          {'name': 'one'}, 
          {'name': 'two'}, 
          {'name': 'foo'}, 
          {'name': 'bar'}, 
          {'name': 'foo'}
        ]
}

The result must be:

{
  subs: [
         {'name': 'foo'}, 
         {'name': 'foo'}
        ]
}

Note that in mongodb client, that query returns this values.

styvane
  • 59,869
  • 19
  • 150
  • 156
Amin
  • 755
  • 6
  • 21
  • Possible duplicate of [Retrieve only the queried element in an object array in MongoDB collection](http://stackoverflow.com/questions/3985214/retrieve-only-the-queried-element-in-an-object-array-in-mongodb-collection) – styvane Feb 24 '16 at 21:24
  • I want do that in mongoengine and python! – Amin Feb 24 '16 at 23:02
  • You will write the same query in mongoengine. – styvane Feb 25 '16 at 07:41

2 Answers2

0

If you are allowed to change your data model then try this:

class Main(Document):
    subs = ListField(StringField())

Main.objectsfilter(subs__ne="foo")

I propose this approach assuming that the embedded document only has one field in which case it is redundant.

Will
  • 1,532
  • 10
  • 22
0

MongoEngine provides the .aggregate(*pipeline, **kwargs) method which performs a aggregate function.

MongoDB 3.2 or newer

match = {"$match": {"subs.name": "foo"}}
project = {'$project': {'subs': {'$filter': {'as': 'sub',
                                   'cond': {'$eq': ['$$sub.name', 'foo']},
                                   'input': '$subs'}}}}

pipeline = [match, project]
Main.objects.aggregate(*pipeline)

MongoDB version <= 3.0

{'$redact': {'$cond': [{'$or': [{'$eq': ['$name', 'foo']}, {'$not': '$name'}]},
                       '$$DESCEND',
                       '$$PRUNE']}}
pipeline = [match, redact]
Main.objects.aggregate(*pipeline)
styvane
  • 59,869
  • 19
  • 150
  • 156