Firebase orderByChild query not returning ordered results - firebase

I am trying to use the Firebase orderByChild() function per the documentation example but the queries are not coming back filtered or sorted.
Here is the sample data structure:
"notifications": {
"001": {
"member_id": "abc123",
"created_at": 1424357680681,
"new": true,
"first_name": "Jon",
"last_name": "Snow",
"message": "likes your photo"
},
"002": {
"member_id": "abc456",
"created_at": 1424357680681,
"new": true,
"first_name": "Clark",
"last_name": "Kent",
"message": "likes your comment"
}
}
When a user logs in, I want to query the notifications hash for only the notifications with a member_id that matches the current user's id.
I have tried both versions with and without the "child_added".
Option A:
ref.orderByChild("member_id").equalTo(memberId);
Option B:
ref.orderByChild("member_id").equalTo(memberId)
.on("child_added", function(data) {
console.log("new child id = " + data.key());
});
When I query the notifications hash, the query returns an array of all of the notifications. They are neither limited to the member_id of the current user, nor sorted by member_id. (I can delete the member_id key entirely and the notification will still be returned).
I can always filter the returned array by member_id in-app, but I would really like to get the query working per the documentation.
Any help is appreciated!

I found the problem!
I was under the impression that you could add the query modifiers in place.
I was doing:
ref.orderByChild("member_id").equalTo(memberId);
var sync = $firebase(ref);
It should actually be:
var sync = $firebase(ref.orderByChild("member_id").equalTo(memberId));

Most likely your memberId variable is a number, while you're storing the corresponding value as a string.
If you store numbers as a string, this query won't give any results:
ref.orderByChild("member_id").equalTo(456)
But this one will:
ref.orderByChild("member_id").equalTo('456')
The easiest fix in your snippet of code is coercing the memberId to a string like this:
ref.orderByChild("member_id").equalTo(''+memberId)
See this fiddle for a working sample: http://jsfiddle.net/695rf0vy/

Related

Is it possible to create a JSON Schema that can validate a hashmap / dictionary as opposed to an object?

So if I have an object, let's call it a Person, like:
{
"email": "foo#bar.com",
"first"" "foo",
"last": "bar"
}
This Person object can all be validated quite well with JSON Schema. The issue is when multiple of these are arranged into a dictionary where the email field is used as the key and the object is the value. For example:
{
"foo#bar.com": {
"email": "foo#bar.com",
"first"" "foo",
"last": "bar"
},
"you#your.com": {
"email": "you#your.com",
"first": "Bob",
"last": "Bobton"
},
"me#mine.com": {
"email": "me#mine.com",
"first": "Deb",
"last": "Debbington"
}
}
This is a common way to structure data. Beyond the validation of the Person values, which can be handled well by a JSON Schema, there are a number of validations that would be useful on the dictionary:
The key is an email and can be validated as one.
The value is always a Person.
The key is always identical to the value's email field.
All the keys are unique.
Is it possible to implement these dictionary validations using JSON Schema?
The first two requirements, yes.
You can use patternProperties.
The other two you ask are not possible using JSON Schema. Sorry.
My expectation would be you receive the data in the first form from an API, validate, then map reduce to your desired structure.

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 Filter Nested Array Object in DynamoDB

I am very beginner to AWS DynamoDB, I want to scan the DynamoDB with SENDTO.emailAddress = "first#first.com" as FilterExpression.
The DB Structure looks like this
{
ID
NAME
MESSAGE
SENDTO[
{
name
emailAddress
}
]
}
A Sample Data
{
ID: 1,
NAME: "HELLO",
MESSAGE: "HELLO WORLD!",
SENDTO: [
{
name: "First",
emailAddress: "first#first.com"
},
{
name: "Second",
emailAddress: "second#first.com"
}
]
}
I want to retrieve document that match emailAddress. I tried to scan with filter expression and here is my code to retrieve the data. I am using AWS Javascript SDK.
let params = {
TableName : "email",
FilterExpression: "SENDTO.emailAddress = :emailAddress",
ExpressionAttributeValues: {
":emailAddress": "first#first.com",
}
}
let result = await ctx.docClient.scan(params).promise();
In order to find the item by sendto attribute, you need to know both name and emailAddress attribute value. DynamoDB can't find the data by just one of the attributes in an object (i.e. email attribute value alone).
CONTAINS function can be used to find the data in List data type.
CONTAINS is supported for lists: When evaluating "a CONTAINS b", "a"
can be a list; however, "b" cannot be a set, a map, or a list.
Sample code using Contains:-
var params = {
TableName: "email",
FilterExpression: "contains (SENDTO, :sendToVal)",
ExpressionAttributeValues: {
":sendToVal": {
"name" : "First",
"emailAddress" : "first#first.com"
}
}
};
If you don't know the value of name and emailAddress attribute, you may need to remodel the data to fulfill your use case.
I think that you should create two tables for users and for messages.
The user table has partition_key: user_id and sort_key: email and a field with an array of his messages ids.
The message table has partition_key: message_id and a field with an array of users ids.
When you will get the array of users ids you can use BATCH GET query to get all users of one message.
When you will get the array of message ids you can use BATCH GET query to get all messages of one user.
If you want to get one user by email you can use QUERY method.
Docs

Firebase filter data by name and city in swift2

I´m trying to get data from Firebase depending on the name and city from object.
My firebase tree looks like this:
MYAPP
Object:
- 12837291ß2837(a random ID):
"name": "test"
"city": "Hong Kong"
- 12382133193u2:
"name": "test"
"city": "Paris"
- 2137829128738:
"name": "test2"
"city": "Frankfurt"
So for example i just want to get the Object where the name is "test" and the city is "Hong Kong".
i tried sth like this but i dont get any Data:
let ref = FIRDatabase.database().referenceFromURL("https://myRef")
ref.queryOrderedByChild("Object").queryEqualToValue("test").observeEventType(.ChildAdded) { (snapshot) in
print(snapshot)
}
I also added rules in Firebase like :
".indexOn": "Object"
Two main problems:
your query doesn't match your data structure
you can only filter on one property.
Your query doesn't match your data structure
To sort/filter you first specify the property that you want to filter on and then the filtering operation. Since the value you specify is from the name property, the correct query is:
let ref = FIRDatabase.database().referenceFromURL("https://myRef")
let query = ref.queryOrderedByChild("name").queryEqualToValue("test")
query.observeEventType(.ChildAdded) { (snapshot) in
print(snapshot)
}
You can only filter on one property
Firebase Database only supports ordering/querying on a single properties. See Query based on multiple where clauses in firebase.

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