views:

65

answers:

3

I'm having a problem with the datastore trying to replicate a left join to find items from model a that don't have a matching relation in model b:

class Page(db.Model):
    url = db.StringProperty(required=True)

class Item(db.Model):
    page = db.ReferenceProperty(Page, required=True)
    name = db.StringProperty(required=True)

I want to find any pages that don't have any associated items.

A: 

Did you try it like :

Page.all().filter("item_set = ", None)

Should work.

anand
No, that doesn't work.
Craig
Also tried .filter("item_set.count() = ", 0)In both cases nothing is returned (one of the records should be returned).
Craig
+1  A: 

The datastore doesn't support joins, so you can't do this with a single query. You need to do a query for items in A, then for each, do another query to determine if it has any matching items in B.

Nick Johnson
Ok, I assumed there would be a way to do this in the datastore, thanks.
Craig
+3  A: 

You cannot query for items using a "property is null" filter. However, you can add a boolean property to Page that signals if it has items or not:

class Page(db.Model):
    url = db.StringProperty(required=True)
    has_items = db.BooleanProperty(default=False)

Then override the "put" method of Item to flip the flag. But you might want to encapsulate this logic in the Page model (maybe Page.add_item(self, *args, **kwargs)):

class Item(db.Model):
    page = db.ReferenceProperty(Page, required=True)
    name = db.StringProperty(required=True)

    def put(self):
        if not self.page.has_items:
            self.page.has_items = True
            self.page.put()
        return db.put(self)

Hence, the query for pages with no items would be:

pages_with_no_items = Page.all().filter("has_items =", False)
mahmoud