Skip to content

Views

Virtual views are aggregation pipelines, stored in MongoDB, that act as collections for reading operations. You can use the View class the same way as Document for find and aggregate operations.

Here are some examples.

Create a view:

from beanie import Document, View
from pydantic import Field


class Bike(Document):
    type: str
    frame_size: int
    is_new: bool


class Metrics(View):
    type: str = Field(alias="_id")
    number: int
    new: int

    class Settings:
        source = Bike
        pipeline = [
            {
                "$group": {
                    "_id": "$type",
                    "number": {"$sum": 1},
                    "new": {"$sum": {"$cond": ["$is_new", 1, 0]}}
                }
            },
        ]

Init beanie:

import motor.motor_asyncio

from beanie import init_beanie


async def main():
    uri = "mongodb://beanie:beanie@localhost:27017"
    cli = motor.motor_asyncio.AsyncIOMotorClient(uri)
    db = cli.bikes

    await init_beanie(database=db, document_models=[Bike, Metrics],
                      recreate_views=True)

Create bikes:

await Bike(type="Mountain", frame_size=54, is_new=True).insert()
await Bike(type="Mountain", frame_size=60, is_new=False).insert()
await Bike(type="Road", frame_size=52, is_new=True).insert()
await Bike(type="Road", frame_size=54, is_new=True).insert()
await Bike(type="Road", frame_size=58, is_new=False).insert()

Find metrics for type == "Road"

results = await Metrics.find(Metrics.type == "Road").to_list()
print(results)

>> [Metrics(type='Road', number=3, new=2)]

Aggregate over metrics to get the number of all the new bikes:

results = await Metrics.aggregate([{
    "$group": {
        "_id": None,
        "new_total": {"$sum": "$new"}
    }
}]).to_list()

print(results)

>> [{'_id': None, 'new_total': 3}]

A better result could be reached using find query aggregation syntax sugar:

results = await Metrics.all().sum(Metrics.new)

print(results)

>> 3