@@ -299,6 +299,207 @@ These indexes use 0-based indexing.
299299 As described above for :class: `EmbeddedModelField `,
300300 :djadmin: `makemigrations ` does not yet detect changes to embedded models.
301301
302+ Querying ``EmbeddedModelArrayField ``
303+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
304+
305+ There are a number of custom lookups and a transform for
306+ :class: `EmbeddedModelArrayField `, similar to those available
307+ for :class: `ArrayField `.
308+ We will use the following example model::
309+
310+ from django.db import models
311+ from django_mongodb_backend.fields import EmbeddedModelArrayField
312+
313+
314+ class Tag(EmbeddedModel):
315+ label = models.CharField(max_length=100)
316+
317+ class Post(models.Model):
318+ name = models.CharField(max_length=200)
319+ tags = EmbeddedModelArrayField(Tag)
320+
321+ def __str__(self):
322+ return self.name
323+
324+ Embedded field lookup
325+ ^^^^^^^^^^^^^^^^^^^^^
326+
327+ Embedded field lookup for :class: `EmbeddedModelArrayField ` allow querying
328+ fields of the embedded model. This is done by composing the two involved paths:
329+ the path to the ``EmbeddedModelArrayField `` and the path within the nested
330+ embedded model.
331+ This composition enables generating the appropriate query for the lookups.
332+
333+ .. fieldlookup :: embeddedmodelarrayfield.in
334+
335+ ``in ``
336+ ^^^^^^
337+
338+ Returns objects where any of the embedded documents in the field match any of
339+ the values passed. For example:
340+
341+ .. code-block :: pycon
342+
343+ >>> Post.objects.create(
344+ ... name="First post", tags=[Tag(label="thoughts"), Tag(label="django")]
345+ ... )
346+ >>> Post.objects.create(name="Second post", tags=[Tag(label="thoughts")])
347+ >>> Post.objects.create(
348+ ... name="Third post", tags=[Tag(label="tutorial"), Tag(label="django")]
349+ ... )
350+
351+ >>> Post.objects.filter(tags__label__in=["thoughts"])
352+ <QuerySet [<Post: First post>, <Post: Second post>]>
353+
354+ >>> Post.objects.filter(tags__label__in=["tutorial", "thoughts"])
355+ <QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
356+
357+ .. fieldlookup :: embeddedmodelarrayfield.len
358+
359+ ``len ``
360+ ^^^^^^^
361+
362+ Returns the length of the embedded model array. The lookups available afterward
363+ are those available for :class: `~django.db.models.IntegerField `. For example:
364+
365+ .. code-block :: pycon
366+
367+ >>> Post.objects.create(
368+ ... name="First post", tags=[Tag(label="thoughts"), Tag(label="django")]
369+ ... )
370+ >>> Post.objects.create(name="Second post", tags=[Tag(label="thoughts")])
371+
372+ >>> Post.objects.filter(tags__len=1)
373+ <QuerySet [<Post: Second post>]>
374+
375+ .. fieldlookup :: embeddedmodelarrayfield.exact
376+
377+ ``exact ``
378+ ^^^^^^^^^
379+
380+ Returns objects where **any ** embedded model in the array exactly matches the
381+ given value. This acts like an existence filter on matching embedded documents.
382+
383+ .. code-block :: pycon
384+
385+ >>> Post.objects.create(
386+ ... name="First post", tags=[Tag(label="thoughts"), Tag(label="django")]
387+ ... )
388+ >>> Post.objects.create(name="Second post", tags=[Tag(label="tutorial")])
389+
390+ >>> Post.objects.filter(tags__label__exact="tutorial")
391+ <QuerySet [<Post: Second post>]>
392+
393+ .. fieldlookup :: embeddedmodelarrayfield.iexact
394+
395+ ``iexact ``
396+ ^^^^^^^^^^
397+
398+ Returns objects where **any ** embedded model in the array has a field that
399+ matches the given value **case-insensitively **. This works like ``exact `` but
400+ ignores letter casing.
401+
402+ .. code-block :: pycon
403+
404+
405+ >>> Post.objects.create(
406+ ... name="First post", tags=[Tag(label="Thoughts"), Tag(label="Django")]
407+ ... )
408+ >>> Post.objects.create(name="Second post", tags=[Tag(label="tutorial")])
409+
410+ >>> Post.objects.filter(tags__label__iexact="django")
411+ <QuerySet [<Post: First post>]>
412+
413+ >>> Post.objects.filter(tags__label__iexact="TUTORIAL")
414+ <QuerySet [<Post: Second post>]>
415+
416+ .. fieldlookup :: embeddedmodelarrayfield.gt
417+ .. fieldlookup :: embeddedmodelarrayfield.gte
418+ .. fieldlookup :: embeddedmodelarrayfield.lt
419+ .. fieldlookup :: embeddedmodelarrayfield.lte
420+
421+ ``Greater Than, Greater Than or Equal, Less Than, Less Than or Equal ``
422+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
423+
424+ These lookups return objects where **any ** embedded document contains a value
425+ that satisfies the corresponding comparison. These are typically used on
426+ numeric or comparable fields within the embedded model.
427+
428+ Examples:
429+
430+ .. code-block :: pycon
431+
432+ Post.objects.create(
433+ name="First post", tags=[Tag(label="django", rating=5), Tag(label="rest", rating=3)]
434+ )
435+ Post.objects.create(
436+ name="Second post", tags=[Tag(label="python", rating=2)]
437+ )
438+
439+ Post.objects.filter(tags__rating__gt=3)
440+ <QuerySet [<Post: First post>]>
441+
442+ Post.objects.filter(tags__rating__gte=3)
443+ <QuerySet [<Post: First post>, <Post: Second post>]>
444+
445+ Post.objects.filter(tags__rating__lt=3)
446+ <QuerySet []>
447+
448+ Post.objects.filter(tags__rating__lte=3)
449+ <QuerySet [<Post: First post>, <Post: Second post>]>
450+
451+ .. fieldlookup :: embeddedmodelarrayfield.all
452+
453+ ``all ``
454+ ^^^^^^^
455+
456+ Returns objects where **all ** values provided on the right-hand side are
457+ present. It requires that *every * value be matched by some document in
458+ the array.
459+
460+ Example:
461+
462+ .. code-block :: pycon
463+
464+ Post.objects.create(
465+ name="First post", tags=[Tag(label="django"), Tag(label="rest")]
466+ )
467+ Post.objects.create(
468+ name="Second post", tags=[Tag(label="django")]
469+ )
470+
471+ Post.objects.filter(tags__label__all=["django", "rest"])
472+ <QuerySet [<Post: First post>]>
473+
474+ Post.objects.filter(tags__label__all=["django"])
475+ <QuerySet [<Post: First post>, <Post: Second post>]>
476+
477+ .. fieldlookup :: embeddedmodelarrayfield.contained_by
478+
479+ ``contained_by ``
480+ ^^^^^^^^^^^^^^^^
481+
482+ Returns objects where the embedded model array is **contained by ** the list of
483+ values on the right-hand side. In other words, every value in the embedded
484+ array must be present in the given list.
485+
486+ Example:
487+
488+ .. code-block :: pycon
489+
490+ Post.objects.create(
491+ name="First post", tags=[Tag(label="django"), Tag(label="rest")]
492+ )
493+ Post.objects.create(
494+ name="Second post", tags=[Tag(label="django")]
495+ )
496+
497+ Post.objects.filter(tags__label__contained_by=["django", "rest", "api"])
498+ <QuerySet [<Post: First post>, <Post: Second post>]>
499+
500+ Post.objects.filter(tags__label__contained_by=["django"])
501+ <QuerySet [<Post: Second post>]>
502+
302503 ``ObjectIdAutoField ``
303504---------------------
304505
0 commit comments