I'm trying to query for all objects that have no value for a given repeated property.
For example imagine you have the following model:
class Foo(ndb.Model):
bar = ndb.IntegerProperty(repeated=True)
and you wanted all the instances of Foo where bar had no value, or is []. How would you perform this query or work around this behavior?
Note (from GAE's ndb documentation):
Querying for a value of None on a repeated property has undefined
behavior; don't do that
Well, like the docs say, you can't.
One way of approaching this might be to keep another property on the model that records how many values it has in bar. You would need to update this when the entity is saved: a good way would be to override put() to do self.bar_count = len(self.bars) before calling the superclass method.
Of course, you'd then need to go through your existing data to set the counts; you might want to use a mapper to do that.
Related
Let's say I use objectify to load() an entity from datastore, then "modify" properties, then save() it back to datastore.
Let's assume no property has changed, e.g. a property has been "overwritten" with it's previous value.
Would objectify still execute the save() or is smart enough to realize there were no real changes and omit saving.
In other words: Does objectify assume there is a change only because I write a property, or will it actually look at the property to determine if there was a material change?
In short, your question is: Does Objectify provide dirty change detection?
No, it doesn't. At least not currently. This is mildly annoying sometimes, especially when you want to call several methods that may change an object - you don't want to execute multiple saves.
I've taken to writing code like this in my entities:
public void setFoo(final String value) {
if (!Objects.equals(this.foo, value)) {
this.foo = value;
ofy().defer().save().entity(this);
}
}
Which is a sort of poor-man's dirty change detection.
Within backbone I have a collection. Where I want to update a model or models within it if a model has a particular attribute value.
I know I can do something to the extent of
var model = myCollection.where({some_attr:'something'});
where model becomes the child object from the collection. However beyond that I seem to get lost. As none of the backbone functions seem to work on it. Example, I can't:
model.set({other_attr: 'changed value'});
model.save();
I just get an Uncaught TypeError. model.set is not a function
again.. Example sake.
So overall I want to find the model, update it, and then save it and its changes to the server? Idea's? Assume I have no workable ID to make getting and setting a little easier, hence why I need to do a where and update like that.
I would recommend using where and always working with the array of models it passes. When you're done updating the models you can make a sync call on the collection to bulk update those changes back to the server.
myCollection.
where({some_attr:'something'}).
map(function(model) {
model.set({other_attr: 'changed value'});
});
myCollection.sync('update');
The statement
var model = myCollection.where({some_attr:'something'});
returns an array of models, not a single model. Assuming only one model will match your criteria, you could use
var model = myCollection.findWhere({some_attr:'something'});
If your collection could have multiple matching models, then you'll want to stick with .where but iterate over the array.
When working with datastore entities in App Engine, people have noticed odd behavior after a put operation is performed on an entity if you choose to hold on to a reference of that entity.
For example, see this issue where repeated String properties mutated to _BaseValue after a put was performed.
In the ensuing discussion, in reference to a repeated String property, Guido van Rossum writes:
"I see. We should probably document that you're not supposed to hang
on to the list of items for too long; there are various forms of
undefined behavior around that."
I get the sense from this thread that it's not a good idea to maintain reference to an entity for too long after a put, as unexpected behavior might arise.
However, when I look at the GAE source code for the Model.get_or_insert() method, I see the following code (docstring removed):
#classmethod
def get_or_insert(cls, key_name, **kwds):
def txn():
entity = cls.get_by_key_name(key_name, parent=kwds.get('parent'))
if entity is None:
entity = cls(key_name=key_name, **kwds)
entity.put()
return entity
return run_in_transaction(txn)
Notice how a put operation is performed, and the entity is returned post-put. Just above, we saw an example of when this is not recommended.
Can anyone clarify when and when it is not ok to maintain a reference to an entity, post put? Guido seemed to hint that there are various scenarios when this could be a bad idea. Just curious if anyone has seen documentation on this (I cannot find any).
Thanks!
The problem described in the issue is not regarding entities, but rather lists obtained from its properties. You can hold a copy of entity as long as you like. It's just an object.
The issue is caused by some "magical" functionality provided by ndb. Let's take a look at the model definition
from google.appengine.ext.ndb import model
class MyModel(model.Model):
items = model.StringProperty(repeated=True)
What can we say about items property?
It looks like a class attribute, but metaclass logic of model.Model transforms it into an instance attribute.
What type are these instance attributes?
They can be accessed like a list of strings, but they are more complex objects having the logic required for storing and retrieving the data from datastore, validating etc.
This "magic" works well in most cases, but sometimes it doesn't. One of the problematic cases is when you get the reference to items from the instance and try to use it after put was called. Another case, mentioned by Guido, was to pass external list to initialize items property and then try to modify this property by manipulating the external list.
The thing to remember: Model properties in ndb try to behave like their basic types, but they are more complex objects. You can read more about their internals in Writing property subclasses
From my understanding the attributes of a Backbone.js model are supposed to be declared as somewhat private member variables by saying
this.set({ attributeName: attributeValue })
// accessing the value
this.get('attributeName');
But when I am writing functions whitin the actual model it seems much simpler to say like this:
this.attributeName = attributeValue;
// accessing the value
this.attributeName;
Also I would assume that the latter version would be faster to process since it doesn't go through backbone.js's event management.
So I was wondering how you pros do with attributes that are primarily used internally in the model. These are the attributes that one would actually want to be a bit shielded from the outside so having them exposed like in the latter example maybe isn't right still. When I have been looking at examples for the backbone.js view which doesn't have get and set methods it seems fine to do like in the second example. So is there any nice rule of thumb when to use get/set(attribute) or this.attribute when coding within the model? Or maybe an example of a model that makes this clearer?
When to use model.get(property) and model.set(...)
You should use get and set to access the model's data. This means any attributes that are part of the model's serialized representation that is retrieved using fetch and persisted using save.
When to use model.attributes.property
Never.
You should always use get, and especially set, instead of accessing the model.attributes object directly, although I've seen conflicting opinions about this. I believe there is a contract between a model and it's consumers, which guarantees that the consumer can be notified of any changes to the model's data using the change event. If you modify the internal attributes object directly, events are not sent and this contract is broken. Backbone events are very fast, especially if you don't have any listeners attached to them, and it's not a point that benefits from over-optimization on your part.
Although accessing the attributes directly instead of get is quite harmless on it's own, it should be avoided so the attributes object can be considered totally, completely private.
If you absolutely need to prevent some change triggering events, you can use the silent:true option: model.set({key:val}, {silent:true}). This does break the aforementioned contract, and even Backbone's own documentation gives the following caveat:
Note that this is rarely, perhaps even never, a good idea. Passing through a specific flag in the options for your event callback to look at, and choose to ignore, will usually work out better.
When to use model.property
Any properties which are not data, i.e. temporary state variables, calculated properties etc. can be attached directly to the model entity. These properties should be considered temporary and transitive: they can be recreated upon model initialization or during its lifetime, but they should not be persisted, whether public or private. A typical naming convention is to prefix private properties with the _ character as follows:
this._privateProperty = 'foo';
this.publicProperty = 'bar';
Never is an incomplete answer.
Sometimes you want access to the collection of model attributes - whatever those attributes might be. Consider a utility method to perform calcs on attributes, format them for output, etc.
A convenient way to do this is to access model.attributes
Consider one alternative, below:
var attributesNames = ['foo', 'bar', 'baz'];
var attributes = _(attributesNames ).map(function(attr) { return model.get(attr); });
callSomeUtilityMethod(attributes);
Two problems:
We've introduced coupling in the "attributeNames" collection. What if that list changes?
We've lost the association of name/value. We could rewrite the map above, but it becomes more work.
In this scenario, it's much more convenient to do something like this:
callSomeUtilityMethod(model.attributes);
I've finally managed to get a handle on loading information using Silverlight, ADO.NET Entities, and RIA Services, but I'm still having a problem with getting the information about the relationships.
For instance, imagine a product, and that product has several categories of attributes. We'll call them ProductAreas.
The Product object has a property called ProductAreas (as a result of their relationship), but when I call:
ctx.Load(GetProductsQuery());
(Where ctx is my DomainContext), the Product objects returned have the ProductAreas property, but it contains no elements, which is a very serious problem, in my case.
So the question is: How do I get access to these relationships?
I'm not sure what your GetProductsQuery() method does, but you should be able use the .Include('ProductAreas') method in your query. If you update your question with the contents of that method I'll try to help more.
This isn't technically the way this system is supposed to work, but I wanted to expand on your answer, while at the same time giving it the credit it rightfully deserves for leading me where I needed to be.
The solutions was to, in the GetProductsQuery() method use
return this.ObjectContext.Products.Include("ProductAreas");
instead of
return this.ObjectContext.Products;
And in the metadata file, go to the Products class and, just above the ProductAreas property add [Include()], so that it looks like:
[Include()]
public EntityCollection<ProductAreas> ProductAreas;