I created a flatted data structure. When pushing duplicated data whats the accepted pattern for keeping that data up-to-date. Here the data for the groups info is duplicated into the users-groups and the groups tree.
{
"users": ..
"users-groups": ..
"groups": ..
}
When creating a group for a user two updates takes place:
First: push to /groups/group_key
{
"name": "Test Group",
"image: "/testimage.jpg"
}
Second: push to /users-groups/user_uid/group_key
{
"orderNum: 0,
"info": {
"name": "Test Group",
"image: "/testimage.jpg"
}
}
Should keeping this data in the user-groups up-to-date be a job for the client or should a server handle this?
The data in the groups tree will always be the newest and the changes should propagate down to all the users that are members of that group.
Is there any tutorials or reference material for this problem?
note: i'm using this structure because a user can be a member of multiple groups and I don't think it would be a good idea to make possibly several ref.once's to get the data from the /groups/ directly.
You can use multi path update. Just observe reference with function and update all other informations
db.ref("").update({
'/users/dedd': info,
'/users/cdcd': info2
})
You should not have data saved duplicated. Instead you should save reference to group.
Your data should look like this.
{
"users": {
"userkey1": {
"data": {
"name": "",
"firstname": ""
},
"groups": {
"groupkey1": true // true or orderNum value
}
}
},
"groups": {
"groupkey1": {
"data": {
"name": "Test Group",
"image": "/testimage.jpg",
"other": "data"
},
"users": {
"userkey1": true
}
}
}
}
You can easily check if user is in group by checking if value at any of these positions is true.
users/userkey1/groups/groupkey1 or groups/groupkey1/users/userkey1.
When you create new group you save in under groups/newgroupkey position and you updated groups under users node by only setting newgroupkey to true.
So you do not duplicate your data.
For more information about structuring your data check the following link.
https://firebase.google.com/docs/database/android/structure-data
Related
Referring to the default sample schema mentioned in https://hasura.io/hub/project/hasura/hello-world/data-apis i.e. to the following two tables:
1) author: id,name
2) article: id, title, content, rating, author_id
where article:author_id has an array relationship to author:id.
How do I make a query to select authors who have written at least one article? Basically, something like select author where len(author.articles) > 0
TL;DR:
There's no length function that you can use in the Hasura data API syntax right now. Workaround 1) filter on a property that is guaranteed to be true for every row. Like id > 0. 2) Build a view and expose APIs on your view.
Option 1:
Use an 'always true' attribute as a filter.
{
"type": "select",
"args": {
"table": "author",
"columns": [
"*"
],
"where": {
"articles": {
"id": {
"$gt": "0"
}
}
}
}
}
This reads as: select all authors where ANY article has id > 0
This works because id is an auto-incrementing int.
Option 2:
Create a view and then expose data APIs on them.
Head to the Run SQL window in the API console and run a migration:
CREATE VIEW author_article_count as (
SELECT au.*, ar.no_articles
FROM
author au,
(SELECT author_id, COUNT(*) no_articles FROM article GROUP BY author_id) ar
WHERE
au.id = ar.author_id)
Make sure you mark this as a migration (a checkbox below the RunSQL window) so that this gets added to your migrations folder.
Now add data APIs to the view, by hitting "Track table" on the API console's schema page.
Now you can make select queries using no_articles as the length attribute:
{
"type": "select",
"args": {
"table": "author_article_count",
"columns": [
"*"
],
"where": {
"no_articles": {
"$gt": "0"
}
}
}
}
So, let's say I have data like this:
{
"events" : {
"s0d980983s" :
{ creator: "bob#bob.com",
text: "Bob says 'My name is Robert'" },
"kjl34jl234j" :
{ creator: "fred#fred.com",
text: "Fred says 'My name is Fredrick'" }
}
"users" : {
"bob#bob.com" : { "paid": true },
"fred#fred.com" : { "paid": false }
}
}
I'm assuming this is the correct way to structure the data. When the data is created, I use the push() method to create a new key for the data, and then store the creator of the data inside it.
I'd like to make it so that:
I can allow anyone from a group of users to access certain data (and disallow others obviously).
The query is "optimized," meaning if I have thousands of records I am not iterating over all the data.
More concretely, for example, I want lizzie#lizzie.com to be able to see the s0d980983s.
I'm confused how to structure the data, and what my Firebase rules should look like.
Would it be something like this?
{ "events" : {
"s0d980983s" :
{ creator: "bob#bob.com",
viewers: { "bob#bob.com": true,
"lizzie#lizzie.com" : true },
text: "Bob says 'My name is Robert'" },
...
}
I don't understand how I can search for events that are viewable by a group of users. I don't believe Firebase supports some kind of wildcard that would make this code work, right?
var ref = firebase.database().ref( "events/*/viewers/lizzie#lizzie.com" ).on(...);
Do I also want to reference the events inside my users table? I'm not sure I understand how to flatten data (denormalize it) and keep references in both places to support a query like this. Should I expect to make multiple queries where I first retrieve a list of events stored in a user object and then retrieve them one by one using their key? But, how do I put that logic into my firebase rules?
{ "events" : {
"s0d980983s" :
{ creator: "bob#bob.com",
viewers: { "[insert bobs id]": true,
"[insert liz id]" : true
},
text: "Bob says 'My name is Robert'" },
...
}
Based on the above structure as you suggested, and if you are using firebase authentication to authenticate your user, you can add another 'read' or 'write' rule for checking whether that user is in the list of your 'viewers'. something like:
{
"rules": {
"users": {
"$uid": {
".write": "auth != null &&
root.child('users').child(auth.uid).child('viewers').child(auth.uid).val() ==
true"
}
}
}
}
This should help. setting firebase security rules at a location/node
Is there any way in Kibana to omit the dashboard time from a particular query? The example use case:
I track open sessions, and want to see how many are currently open. The sessions like all the objects I log are imported against their create date. But they also have an expired date.
I want to ignore the creation date and just show sessions that have not expired yet.
I've got the query part like this one from ES:
GET /dev/authority/_search
{
"query": {
"filtered": {
"filter": {
"and": [
{
"term": {
"_type": "authority"
}
},
{
"term": {
"enabled": true
}
},
{
"term": {
"_issuedTo.userType": "customer"
}
},
{
"range": {
"expires": {
"gt": "now"
}
}
}
]
}
}
}
}
The problem is that the dashboard is acting like a "between" filter, so it only gets sessions that were created after the dashboard start time. I want to ignore this value and get all matches regardless of create time, can it be done?
No, you can't.
The time filter applies to all the widgets in the dashboard.
When you create index pattern you can specify any date field as Timed-field:
And from right up corner you can change time interval for time series data:
Click it and choose whatever you want.
I have a Players collection and a Games collection. I want to construct a data structure that looks as follows:
{
"_id": "1234",
"accounts": {
"battlenet": "blah#1234"
},
"games": {
"overwatch": {
"class": "Hanzo",
"timePlayed": ISODate
},
"world-of-warcraft": {
"class": "Shaman",
"timePlayed": ISODate
}
}
}
games is an object, where every key refers to a specific document in the Games collection's slug attribute. Every value is a sub-schema definition with autoValues.
I can't find any good way to create validation in such a way that it updates an autoform correctly without weird coersion of data. Is there any way to accomplish this validation with simple schema?
In the Firebase security rules file, could one effectively use the '.validate' directives to synchronize schema, that is, make sure when one part of the Firebase is modified, another part gets updated as well? Or is this a bad/invalid idea?
Basically what I'm trying to do is create a Todo list app. I want to be able to create tasks in my todo list with specified tags. For each tag in the app, there should be a respective tag child field in the "tags" field in my Firebase backend. The tag field should contain an ordered list of references to tasks in the "tasks" field. So, if a task is created with "#foo" tag, then it's name (id) should be referenced in "tasks/foo". Also, whenever a task is removed, it's reference in each tag should be removed, and when a tag in has no children it should be removed.
To clarify here's an example of the schema:
{
"tasks": {
"-sdjfaowneono": {
"headline": "Get some milk",
"completed": false,
"tags": {
"0": "all",
"1": "shopping"
}
},
"-asdfhsadfsafwirn": {
"headline": "Pick up the kids",
"completed": false,
"tags": {
"0": "all"
}
}
},
"tags": {
"all": {
"0": "-sdjfaowneono",
"1": "-asdfhsadfsafwirn"
},
"shopping": {
"0": "-sdjfaowneono"
}
}
}
Again, if task "-sdjfaowneono" was removed, so would the "shopping" tag be removed.
In conclusion, I need to synchronize the "tags" schema with the "tasks" schema in a specific way. Should I do this synchronization in the Security Rules? Or should I do this at the app level? And if I do it at the app level, there is a risk that the app bugs out and doesn't add/remove a tag which it should, so how do I overcome that?
To use this with security rules, you will need to change one or the other to use the tag id as the key, rather than an array value, since there is no way to specify a wild card or search multiple children to see if one contains the correct value.
So if you changed your "tags" path to look like this:
"tags": {
"all": {
"-sdjfaowneono": true,
"-asdfhsadfsafwirn": true
},
"shopping": {
"-sdjfaowneono": true
}
}
Then you could validate like this:
"tasks": {
"$task": {
"tags": {
"$tag": {
".validate": "root.child('tags/'+newData.val()+'/'+$task).exists()"
}
}
}
}
This uncovers a basic design practice that I've discovered while building with Firebase: I tend to prefer keys to values for storing any sort of foreign key reference.
Also, keep in mind that this only enforces that they match up on write. It does help with deletions since .validate will only run if the value exists.
You could enforce the same behavior on deletions by appending this to the write rule:
".write": " ... && (newData.exists() || !root.child('tags/'+newData.val()+'/'+$task).exists())"