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 pydantic import Field

from bunnet import Document, View


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]}}
                }
            },
        ]

Initialize Bunnet:

from pymongo import MongoClient
from bunnet import init_bunnet


def main():
    uri = "mongodb://bunnet:bunnet@localhost:27017"
    client = MongoClient(uri)
    db = client.bikes

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

Create bikes:

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

Find metrics for type == "Road"

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

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

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

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

print(results)

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

A better result can be achieved by using find query aggregation syntactic sugar:

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

print(results)

>> 3