Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongoengine - query how to filter by ListField size

I have the following model:

class Like(EmbeddedDocument):
    user = ReferenceField(User,dbref=False)
    date = DateTimeField(default=datetime.utcnow,required=True)
    meta = {'allow_inheritance': False}

class Post(Document):
   name = StringField(max_length=120, required=True)
   likes = ListField(EmbeddedDocumentField(Like))

I would like to filter only Posts with more than 20 likes (ListField size greater than 20). I've tried to query using:

posts = Post.objects.filter(likes__size_gte=20)
posts = Post.objects.filter(likes_gte=20)
posts = Post.objects.filter(likes__gte=20)
posts = Post.objects.filter(likes__size_gte=20)

None of them work.

But if I use the exact match (ListField size exactly 20 likes) it works:

posts = Post.objects.filter(likes__size=20) 

Comments?

like image 684
rat Avatar asked Feb 21 '13 22:02

rat


2 Answers

Far from being the perfect solution, but you can do with a raw mongo query and the $where operator, for example:

posts = Post.objects.filter(__raw__={'$where': 'this.likes.length > 20'})

Another option, which should work faster, but is less clear in my opinion, is to check whether the 21th element exists:

posts = Post.objects.filter(likes__21__exists=True)

The second option only works if you're using MongoDB 2.2+

Source: Taken from these answers and applied to MongoEngine.

like image 97
yprez Avatar answered Oct 29 '22 05:10

yprez


You can't use $size for a range of values.

From mongo's site:

$size does not accept ranges of values. To select documents based on fields with different numbers of elements, create a counter field that you increment when you add elements to a field.

This is the link to the related question that led to the answer: remove documents with array field's size less than 3 in mongoDB

This is the mongo page that the previous link linked to that gave the documentation in the block up above: http://docs.mongodb.org/manual/reference/operator/size/#_S_size

Try adding a counter field as suggested in the text block.

like image 40
egreene Avatar answered Oct 29 '22 04:10

egreene