How to test for unset repeated properties in NDB?
Asked Answered
F

1

6

How to I test for unset repeated properties in NDB after entity has been set?

The only reference I can find says:

Querying for a value of None on a repeated property has undefined behavior; don't do that.

Fastidious answered 18/12, 2012 at 8:48 Comment(2)
What do you mean by "test for unset"? Do you mean query entities that do not have a certain value in their repeated property or that have no values in repeated property?Sessions
Sorry for vague phrasing. Yes, I mean doing the equivalent of my_propery = null.Fastidious
S
9

If you never add anything to the contents of the list in a repeated property, no value will be sent, and the property will show up as <missing> not as <null>

According to the App Engine documentation on Queries and Indexes, there is a distinction between entities that have no value for a property, and those that have a null value for it; and

Entities Without a Filtered Property Are Never Returned by a Query.

So it is not possible to write a query for these old records.

See the rest of the answer quoted above at
AppEngine: Query datastore for records with <missing> value

If you want to be able to query for such things, you should enforce this in your data model. For example you could have a ndb.ComputedProperty which is a boolean corresponding to whether or not the corresponding list has length zero, e.g.

class MyModel(ndb.Model):
  my_repeat = ndb.StringProperty(repeated=True)
  sentinel = ndb.ComputedProperty(lambda self: len(self.my_repeat) == 0)

and to query for these missing values, you could use

MyModel.query(MyModel.sentinel == True)

If you have an existing set of such objects in your datastore, you can run a one-time mapreduce over them and simply retrieve each entity using the updated model definition and then put each back into the datastore. This will keep all existing properties the same and update with the sentinel value.

Statistical answered 18/12, 2012 at 17:6 Comment(1)
Is there any reason you're using a decorator instead of calling it directly was sentinel = ndb.ComputedProperty(lambda self: len(self.my_repeat) == 0) ?Fastidious

© 2022 - 2024 — McMap. All rights reserved.