Saving JSON as a value inside embedded entities in Cloud Datastore - google-cloud-datastore

In Google Cloud Store entities - is there a way to store JSON as the VALUE of an embedded entity property?
For example, I would expect something like this:
{
"properties": {
"someObject": {
"objectValue": {"some":"sutome","json":"object"}
}
}
}
objectValue would be the type of the property
Thanks

In Google Cloud Store entities - is there a way to store JSON as the VALUE of an embedded entity property?
Not directly. However, what you can do is stringify the JSON object and store it as a StringValue (just remember to parse the value back into a JSON object once you retrieve it). Note that if the property that stores the string value is indexed the maximum size the string can be is 1500 bytes, if the property is not indexed the max size of the string is 1MB(1,000,000 bytes).

Related

Can I run a firestore query on a key that doesn't exist? [duplicate]

Let's say I have a data model with some optional properties. This could be for example a user object with a "firstname", a "lastname" and an optional "website" property.
In Cloud Firestore only user documents with a known website would have the "website" property set, for all other user documents this property would not exist.
My questions is now, how to query for all user documents without a "website" property?
Documents can contain properties with a null value data type (see data types documentation). This will then allow you to construct a query to limit results where the website property is null.
This is not quite the same as a missing property, but if you use custom objects to write data to Firestore, empty properties will automatically be saved as null rather than not at all. You can also manually/programmatically write a null value to the database.
In Android, I tested this using the following:
FirebaseFirestore.getInstance().collection("test").whereEqualTo("website", null).get();
Where my database structure looked like:
This returned only the document inuwlZOvZNTHuBakS6GV, because document 9Hf7uwORiiToOKz6zcsX contains a string value in the website property.
I believe you usually develop in Swift, where unfortunately custom objects aren't supported, but you can use NSNull() to write a null value to Firestore. For example (I'm not proficient in Swift, so feel free to correct any issues):
// Writing data
let docData: [String: Any] = [
"firstname": "Example",
"lastname": "User",
"website": NSNull()
]
db.collection("data").document("one").setData(docData) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Document successfully written!")
}
}
// Querying for null values
let query = db.collection("test").whereField("website", isEqualTo: NSNull())
The documentation doesn't mention a method to query for values that don't exist, so this seems like the next best approach. If anyone can improve or suggest alternatives, please do.

Objectify Web Safe Key Usage

I am using Objectify to store and retrieve data from App Engine Datastore.
String version of the key is created from the datastore object id.
public String getWebsafeKey() {
return Key.create(UserData.class, id).getString();
}
The websafeKey is used to get the UserData object from the Datastore.
Key<UserData> userDataKey = Key.create(websafeKey);
UserData userData = ofy().load().key(userDataKey).now();
In our Unit testing when the websafeKey is changed a bit, the user data class can still be retrieved.
Passed websafeKey - agxqfmMyaHF1YWxpdHlyEgsSBU1vdmllGICAgJDSioELDC
Actual websafeKey - agxqfmMyaHF1YWxpdHlyEgsSBU1vdmllGICAgJDSioELDA
Is this a known limitation or this can be addressed?
websafeKey's are base64 encoded strings.
Somehow both
agxqfmMyaHF1YWxpdHlyEgsSBU1vdmllGICAgJDSioELDC &
agxqfmMyaHF1YWxpdHlyEgsSBU1vdmllGICAgJDSioELDA decode to jj~c2hqualityrMovie
give it a try https://www.base64decode.org/

Firestore: How to query for non-existing (undefined) fields? [duplicate]

Let's say I have a data model with some optional properties. This could be for example a user object with a "firstname", a "lastname" and an optional "website" property.
In Cloud Firestore only user documents with a known website would have the "website" property set, for all other user documents this property would not exist.
My questions is now, how to query for all user documents without a "website" property?
Documents can contain properties with a null value data type (see data types documentation). This will then allow you to construct a query to limit results where the website property is null.
This is not quite the same as a missing property, but if you use custom objects to write data to Firestore, empty properties will automatically be saved as null rather than not at all. You can also manually/programmatically write a null value to the database.
In Android, I tested this using the following:
FirebaseFirestore.getInstance().collection("test").whereEqualTo("website", null).get();
Where my database structure looked like:
This returned only the document inuwlZOvZNTHuBakS6GV, because document 9Hf7uwORiiToOKz6zcsX contains a string value in the website property.
I believe you usually develop in Swift, where unfortunately custom objects aren't supported, but you can use NSNull() to write a null value to Firestore. For example (I'm not proficient in Swift, so feel free to correct any issues):
// Writing data
let docData: [String: Any] = [
"firstname": "Example",
"lastname": "User",
"website": NSNull()
]
db.collection("data").document("one").setData(docData) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Document successfully written!")
}
}
// Querying for null values
let query = db.collection("test").whereField("website", isEqualTo: NSNull())
The documentation doesn't mention a method to query for values that don't exist, so this seems like the next best approach. If anyone can improve or suggest alternatives, please do.

JSON Structure to insert a null value for a property into Google Cloud Datastore

What JSON Structure is used to insert a null value for a property into Google Cloud Datastore using the REST API?
Usually you define a property name, valuetype, and value, like so:
var property = {
propertyname: { integerValue: 4 }
};
With integerValue denoting the valuetype. All the valuetypes can be seen here but I can not work out the structure for null.
This is a bug in the JSON API.
I've filed https://github.com/GoogleCloudPlatform/google-cloud-datastore/issues/41 to track it.
In the proto API, you would do this:
Property property = Property.newBuilder()
.setName("propertyName")
.setValue(Value.getDefaultInstance())
.build();

Different RavenDB collections with documents of same type

In RavenDB I can store objects of type Products and Categories and they will automatically be located in different collections. This is fine.
But what if I have 2 logically completely different types of products but they use the same class? Or instead of 2 I could have a generic number of different types of products. Would it then be possible to tell Raven to split the product documents up in collections, lets say based on a string property available on the Product class?
Thankyou in advance.
EDIT:
I Have created and registered the following StoreListener that changes the collection for the documents to be stored on runtime. This results in the documents correctly being stored in different collections and thus making a nice, logically grouping of the documents.
public class DynamicCollectionDefinerStoreListener : IDocumentStoreListener
{
public bool BeforeStore(string key, object entityInstance, RavenJObject metadata)
{
var entity = entityInstance as EntityData;
if(entity == null)
throw new Exception("Cannot handle object of type " + EntityInstance.GetType());
metadata["Raven-Entity-Name"] = RavenJToken.FromObject(entity.TypeId);
return true;
}
public void AfterStore(string key, object entityInstance, RavenJObject metadata)
{
}
}
However, it seems I have to adjust my queries too in order to be able to get the objects back. My typical query of mine used to look like this:
session => session.Query<EntityData>().Where(e => e.TypeId == typeId)
With the 'typeId' being the name of the new raven collections (and the name of the entity type saved as a seperate field on the EntityData-object too).
How would I go about quering back my objects? I can't find the spot where I can define my collection at runtime prioring to executing my query.
Do I have to execute some raw lucene queries? Or can I maybe implement a query listener?
EDIT:
I found a way of storing, querying and deleting objects using dynamically defined collections, but I'm not sure this is the right way to do it:
Document store listener:
(I use the class defined above)
Method resolving index names:
private string GetIndexName(string typeId)
{
return "dynamic/" + typeId;
}
Store/Query/Delete:
// Storing
session.Store(entity);
// Query
var someResults = session.Query<EntityData>(GetIndexName(entity.TypeId)).Where(e => e.EntityId == entity.EntityId)
var someMoreResults = session.Advanced.LuceneQuery<EntityData>(GetIndexName(entityTypeId)).Where("TypeId:Colors AND Range.Basic.ColorCode:Yellow)
// Deleting
var loadedEntity = session.Query<EntityData>(GetIndexName(entity.TypeId)).Where(e =>
e.EntityId == entity.EntityId).SingleOrDefault();
if (loadedEntity != null)
{
session.Delete<EntityData>(loadedEntity);
}
I have the feeling its getting a little dirty, but is this the way to store/query/delete when specifying the collection names runtime? Or do I trap myself this way?
Stephan,
You can provide the logic for deciding on the collection name using:
store.Conventions.FindTypeTagName
This is handled statically, using the generic type.
If you want to make that decision at runtime, you can provide it using a DocumentStoreListner

Resources