Getting all root properties - azure-cosmosdb

Let's say I have a DocumentDB collection populated with documents that have this shape:
[{ "Name": "KT", "Dob": "5/25/1990", "Children": [], "IsMale": false },
{ "Name": "Chris", "Dob": "10/1/1980", "Children": [], "IsMale": true }]
Now let's say I don't the structure of the documents above.
Is there a query I can write that will return me a distinct list of those property names ("Name", "Dob", "Children", "IsMale")?
In other words, is there a way for be to sniff out the schema of those documents?

This might be a duplicate of this question. In any case, the answers there might give you some ideas.
tl;dr; The only way to do it is to read all of the docs. You can pull them all back to your machine or you can read them inside of a stored procedure and only send the calculated schema back to your machine.

You need a dynamic ORM or ODM for Azure DocumentDB like Slazure to do something like this. Example follows:
using SysSurge.Slazure.AzureDocumentDB.Linq;
using SysSurge.Slazure.Core;
using SysSurge.Slazure.Core.Linq.QueryParser;
public void EnumProperties()
{
// Get a reference to the collection
dynamic storage = new QueryableStorage<DynDocument>("URL=https://contoso.documents.azure.com:443/;DBID=DDBExample;TOKEN=VZ+qKPAkl9TtX==");
QueryableCollection<DynDocument> collection = storage.TestCustomers;
// Build collection query
var queryResult = collection.Where("SignedUpForNewsletter = true and Age < 22");
foreach (DynDocument document in queryResult)
{
foreach (KeyValuePair<string, IDynProperty> keyValuePair in document)
{
Console.WriteLine(keyValuePair.Key);
}
}
}

Related

Cosmos SQL API: filter based an array entry

Given the json
{
"fileIds": [
"171824c7-1485-4b35-9418-2b40aea8fa48",
"b158e946-621f-431e-926c-57577e3e0b6b"
],
"eventType": 8,
"description": "File deleted from original storage account",
"registerTimeUtc": "0001-01-01T00:00:00",
"customerId": "c7b00078-8fd7-49ad-989a-2fabcb767f6e",
"applicationId": "266c6ca3-e77c-4233-b780-b8dd69aa7349"
...
}
I need to check if an entry exists based on a given applicationId, eventType and fileId and I do not know how to write the query based on fileId to check its existence in the array list.
Please try the following query:
SELECT * FROM Root r where
r.applicationId = '266c6ca3-e77c-4233-b780-b8dd69aa7349' and
r.eventType = 8 and
ARRAY_CONTAINS(r.fileIds, '171824c7-1485-4b35-9418-2b40aea8fa48')
To search for an item in an array, you will need to use ARRAY_CONTAINS function.

How to query nested objects in firestore [duplicate]

This question already has answers here:
Firestore - Nested query
(2 answers)
Closed 2 years ago.
I want to store data in following format:
{
"chatName": "Football",
"chatMembers":
[
{
"userId": "nSWnbKwL6GW9fqIQKREZENTdVyq2",
"name": "Niklas"
},
{
"userId": "V3QONGrVegQBnnINYHzXtnG1kXu1",
"name": "Timo"
},
]
}
My goal is to get all chats, where the signed in user with a userId is in the chatMembers list. If the userId of the signed in user is not in the chatMembers property, then that chat should be ignored. Is this possible?
If this is not possible, how can i achive this with subcollections?
My development language is dart, but you can also post solutions in other languages.
My current attempt is this, but this is not working:
_firestore.collection(collectionName).where("chatMembers.userId", isEqualTo: userId).snapshots()
Since August 2018 there is the new array_contains operator which allows filtering based on array values. The doc is here: https://firebase.google.com/docs/firestore/query-data/queries#array_membership
It works very well with arrays of string. However, I think it is not possible to query for a specific property of an object stored in the array. One workaround is to query for the entire object, as follows (in Javascript). Of course this may not be feasible in every situation....
var db = firebase.firestore();
var query = db.collection('chatDocs').where("chatMembers", "array-contains", { userId: "xyz", userName: "abc" });
Renaud Tarnec's, which complete, doesn't work in every case. Situations where only one or not all of the fields are known won't return the expected documents. However, by restructuring the data in the document, a query can be made to work where only one field is known, like a user identifier (uid).
Here's the data structure inside one of the document:
{
"members": {
"user4": {
"active": true,
"userName": "King Edward III",
"avatar": "www.photos.gov/animeGirl5.png"
},
"user7": {
"active": true,
"userName": "Dave K.",
"avatar": "www.photos.gov/gunsAmericanFlag.png"
}
}
Here's the query:
uid = 'user4';
collectionQuery = collectionReference.where(`members.${uid}.active`,"==", true);
In this example, "user4" represents a user who may or may not be in a group. This will return all documents in the collection where the uid "user4" is an active member. This works by only needing to know the UID of the member and works without needing to know their name or avatar uri ahead of time.

How to update a nested object inside an array in DynamoDB

Consider the following document item / syntax in a DynamoDB table:
{
"id": "0f00b15e-83ee-4340-99ea-6cb890830d96",
"name": "region-1",
"controllers": [
{
"id": "93014cf0-bb05-4fbb-9466-d56ff51b1d22",
"routes": [
{
"direction": "N",
"cars": 0,
"sensors": [
{
"id": "e82c45a3-d356-41e4-977e-f7ec947aad46",
"light": true,
},
{
"id": "78a6883e-1ced-4727-9c94-2154e0eb6139",
}
]
}
]
}
]
}
My goal is to update a single attribute in this JSON representation, in this case cars.
My approach
I know all the sensors IDs. So, the easiest way to reach that attribute is to find, in the array, the route which has a sensor with any of the ids. Having found that sensor, Dynamo should know which object in the routes array he has to update. However, I cannot run this code without my condition being rejected.
In this case, update attribute cars, where the route has a sensor with id e82c45a3-d356-41e4-977e-f7ec947aad46 or 78a6883e-1ced-4727-9c94-2154e0eb6139.
var params = {
TableName: table,
Key:{
"id": "0f00b15e-83ee-4340-99ea-6cb890830d96",
"name": "region-1"
},
UpdateExpression: "set controllers.intersections.routes.cars = :c",
ConditionExpression: ""controllers.intersections.routes.sensors.id = :s",
ExpressionAttributeValues:{
":c": 1,
":s": "e82c45a3-d356-41e4-977e-f7ec947aad46"
},
ReturnValues:"UPDATED_NEW"
};
docClient.update(params, ...);
How can I achieve this?
Unfortunately, you can't achieve this in DynamoDB without knowing the array index. You have very complex nested structure. The DynamoDB API doesn't have a feature to handle this scenario.
I think you need the array index for controllers, routes and sensors to get the update to work.
Your approach may work in other databases like MongoDB. However, it wouldn't work on DynamoDB. Generally, it is not recommended to have this complex structure in DynamoDB especially if your use case has update scenario.
TableName : 'tablename',
Key : { id: id},
ReturnValues : 'ALL_NEW',
UpdateExpression : 'set someitem['+`index`+'].somevalue = :reply_content',
ExpressionAttributeValues : { ':reply_content' : updateddata }
For updating nested array element need to fing out array index . Then you can update nested array element in dynamo db.

Model entities with firebase

I have the following situation:
I have a team entity, in each team we have one or more users.
At first I thought about creating an array of IDS inside team. And then download all team and use the javascript to go through these IDS and fetch the corresponding user.
Something like that:
"teams": {
"xxxxxxx": {
"ids": [0: "bKvysPZZCudBKbbjLYV8ZKr1NUo1", 1: XOvysPZZCudBKbbjLYV8ZKr1NUo1]
}
}
But I do not know if it is the best solution. I would like your opinion.
Tks.
I would recommend making a dictionary of IDs where each ID maps with the boolean value of true. I.e.:
"team-users": {
"team1": [
"uid1": true,
"uid2": true,
...
]
}
if you want to get a team that a user is a part of, then use a parallel structure in you database. Add the following node:
"user-teams": {
"uid1": [
"team1": true,
"team2": true,
...
]
}
Reading from this separate node is faster than querying.

How to query related records in Firebase?

Given this database structure in Firebase:
{
"users": {
"user1": {
"items": {
"id1": true
}
},
"user2": {
"items": {
"id2": true
}
}
},
"items": {
"id1": {
"name": "foo1",
"user": "user1"
},
"id2": {
"name": "foo2",
"user": "user2"
}
}
}
which is a more efficient way of querying the items belonged to a specific user?
The Firebase docs seem to suggest this:
var itemsRef = new Firebase("https://firebaseio.com/items");
var usersItemsRef = new Firebase("https://firebaseio/users/" + user.uid + "/items");
usersItemsRef.on("child_added", function(data){
itemsRef.child(data.key()).once("value", function(itemData){
//got the item
});
});
but using the .equalTo() query works as well:
var ref = new Firebase("https://firebaseio.com/items");
ref.orderByChild("user").equalTo(user.uid).on("child_added", function(data){
//got the item
});
The latter code seems more concise and doesn't require denormalization of the item keys into the user records but it's unclear to me if it's a less efficient methodology (assuming I create an index on "user").
thanks.
This is rather old one, but when working on the firebase-backed app, I found myself dealing with similar issues quite often.
.equalTo is more time-efficient (especially, if one user owns big number of items). Although n+1 subscriptions does not lead to n+1 networking roundtrips to the cloud, there is some performance penalty for having so many open subscriptions.
Moreover, .equalTo approach does not lead to denormalization of your data.
There is a gotcha however: When you'll want to secure the data, the .equalTo approach may stop working at all.
To allow user to call orderByChild("user").equalTo(user.uid), they must have read privilege to 'items' collection. This read permission is valid for the whole sub-document rooted at /items.
Summary: If user1 is to be prevented from finding out about items of user2, you must use the BYOI (build your own index) approach. That way you can validate that user only reads items that are put to their index.
Finally, disclaimer :) I use firebase only for a short period of time all I got is a few benchmarks and documentation. If I'm mistaken in any way, please correct me.

Resources