Query firebase realtime database where child has property - javascript

I'm trying to query my Firebase Realtime Database to find all games a user belongs to.
I have a list of games, each game has a property of players. Each child of players has a key of $uid, and within that {key: $uid, name: "joe"}
Is it possible to get all games this way? Or do I need to start keeping another index of players_games/$uid/$game?
I've tried firebase.database().ref('games').orderByChild('players').equalTo(token.uid), but this yields null
It looks like database.ref('games').orderByChild('players/${token.uid}') works, but then I'd need to give .read access to all of games, or do this server-side.

Your current data structure makes it easy to find all the users for a specific game. It does not however make it easy to find all the games for a specific user. To allow that, you'll want to add an addition data structure that inverts the information.
So that'd look something like this:
player_games: {
"XDYNyN8il6TDsM4LuttwDzNuytj1": {
"-M5vf...U5zK": true
},
"NxH14...mxY2": {
"-M5vf...U5zK": true
}
}
Also see:
Firebase query if child of child contains a value
Firebase Query Double Nested
I recommend you also study the Firebase documentation on structuring your database, specifically the section on avoiding nested data. By mixing entity types as you currently do, you'll likely run into problems with security, and scalability.
The most idiomatic way to model your many-to-many relationship in the Firebase database is with four top-level lists:
players: {
$playerId: { ... }
}
games: {
$gameId: { ... }
}
player_games: {
$playerId: {
$gameId: true
}
}
game_players: {
$gameId: {
$playerId: true
}
}
Also see:
Many to Many relationship in Firebase

Related

Using Apollo's writeFragment to update nested list

I am working on a application in which a ship can be configured using rudders and other stuff. The database structure is sort of nested, and so far I have been keeping my GraphQL queries in correspondence with the database.
That means: I could fetch a ship using some query ship(projectId, shipId), but instead I am using a nested query:
query {
project(id:1) {
id
title
ship(id:1) {
id
name
rudders {
id
position
}
}
}
}
Such a structure of course leads to a lot of nested arrays. For example, if I have just added a new rudder, I would have to retrieve using cache.readQuery, which gives me the project object rather than the rudder list. To add the rudder to the cache, I'd get a long line with nested, destructured objects, making the code hard to read.
So I thought of using GraphQL fragments. On the internet, I see them being used a lot to prevent having to re-type several fields on extensive objects (which I personally find very useful as well!). However, there are not so many examples where a fragment is used for an array.
Fragments for arrays could save all the object destructuring when appending some data to an array that is nested in some cached query. Using Apollo's readFragment and writeFragment, I managed to get something working.
The fragment:
export const FRAGMENT_RUDDER_ARRAY = gql`
fragment rudderArray on ShipObject {
rudders {
id
position
}
}
`
Used in the main ship query:
query {
project(id: ...) {
id
title
ship(id: ...) {
id
name
...rudderArray
}
}
}
${RUDDER_FRAGMENT_ARRAY}
Using this, I can write a much clearer update() function to update Apollo's cache after a mutation. See below:
const [ createRudder ] = useMutation(CREATE_RUDDER_MUTATION, {
onError: (error) => { console.log(JSON.stringify(error))},
update(cache, {data: {createRudder}}) {
const {rudders} = cache.readFragment({
id: `ShipObject:${shipId}`,
fragment: FRAGMENT_RUDDER_ARRAY,
fragmentName: 'rudderArray'
});
cache.writeFragment({
id: `ShipObject:${shipId}`,
fragment: FRAGMENT_RUDDER_ARRAY,
fragmentName: 'rudderArray',
data: {rudders: rudders.concat(createRudder.rudder)}
});
}
});
Now what is my question? Well, since I almost never see fragments being used for this end, I find this working well, but I am wondering if there's any drawbacks to this.
On the other hand, I also decided to share this because I could not find any examples. So if this is a good idea, feel free to use the pattern!

Is there a way to push data into firebase without having the UID

I wish to create a reporting employee structure, I am using internal keys generated by the push function as EID's and will be nesting reporting employees EID under the reported employees EID. So for Eg. if a manager has a EID: -KbAGV6Uhg0BKK31HduN and a reporting engineer has a EID: -Kb9ioY8dkBEOO46uX7t the Json structure would look like
{
"-KbAGV6Uhg0BKK31HduN " : {
"reportingID" : "-Kb9ioY8dkBEOO46uX7t"
}
}
but because I am using the push function it looks something like this:
{
"-KbAGV6Uhg0BKK31HduN" : {
"-KbAH1RiVsz5FpSFudD2" : {
"reportingID" : "-Kb9ioY8dkBEOO46uX7t"
}
}
}
I don't require this extra key(-KbAH1RiVsz5FpSFudD2)what can be done to avoid it or have something else like E1 or someother easy identifier in its place as the key is making the structure too complicated
What you have described is the Firebase way to handle things if you want to use push.
Instead of pushing, you could use the set method to do something like this:
ManagerID/directReports/EngineerID
where EngineerID could contain some additional info about the engineer or some key:value pair that would be useful to have in the app.
The JSON structure would look like this:
"ManagerGUID":{
"directReports": {
"EngineerGUID":{
"someinfokey":"somevalue"
}
}
}
That way, if you want a list or iterable, you can just download the ManagerID/directReports node and have individual objects using the original key for the engineers. It might make some extra working in transforming to an array, but it sounds like this is kind of what you want to do. Let me know if I'm off base and I can update my answer.
It is not a best practice but you can generate a global unique id for each entry instead of Firebase generated uid.
Have a look a one of id generator here: https://gist.github.com/mikelehen/3596a30bd69384624c11

Setting up data structure for querying in Firebase

I am currently creating an app where the administrator should be able to tag images. The visitors can search for a tag, and see the images that have that tag.
One image can have more than one tag. This represents how I currently have set up my data:
Images: {
PUSH_ID: {
url: "https://cdn.filestackcontent.com/o0ze07FlQjabT9nuteaE",
tags: {
PUSH_ID: {
tag: "1324"
},
PUSH_ID: {
tag: "4321"
}
}
}
}
When a visitor searches for a tag, I need to be able to query the tag, and find the URL of the images that have the given tag. I was thinking that something along the lines of this would work:
ref.orderByChild('tags/tag').equalTo(tag).once("value"...)
But after some reading I have come to the understanding that you can only query one level deep in Firebase.
If this is the case, I need to restructure my data, but I cannot figure out how it should be structured.
Can anyone help me?
Btw; I have been told that I should use something like Elasticsearch to query in Firebase, but this app is for an event with a limited ammount of traffic.
Thanks!
When modeling data in Firebase (and in most NoSQL databases), you need to model the data for how your app wants to use it.
For example:
Images: {
PUSH_ID_1: {
url: "https://cdn.filestackcontent.com/o0ze07FlQjabT9nuteaE",
tags: {
"tag1324": true,
"tag4321": true
}
},
PUSH_ID_2: {
url: "https://cdn.filestackcontent.com/shjkds7e1ydhiu",
tags: {
"tag1324": true,
"tag5678": true
}
}
},
TagsToImages: {
"tag1324": {
PUSH_ID_1: true,
PUSH_ID_2: true
},
"tag4321": {
PUSH_ID_1: true
}
"tag5678": {
PUSH_ID_2: true
}
}
I changed a few things from you model:
I still store the tags for each image, so that you can show them when a user is watching a single image
But now we store the tags in a "tag1234": true format, which prevents a image from being tagged with the same tag multiple times. Whenever you feel the need for an array that you want to do a contains() operation on, consider using this approach which is more akin to a set.
I prefix the tag numbers with a static string, which prevents Firebase from trying to interpret the tag numbers as array indices.
We now also store a map of tags-to-image-ids. In this map you can easily look up all image IDs for a specific tag and then load the images in a loop.
We've essentially duplicated some data (the tags are stored twice) to ensure that we can look the information up in two ways. If you have more ways you want to access the data, you may need to replicate even more. This is normal in NoSQL databases and is part of the reason they scale so well.
I highly recommend reading this article on NoSQL data modeling.
And there is a Tags node in this structure like this, isnt it??
Tags: {
"tag1324": {
tagName: pets
},
"tag4321": {
tagName: daffodil
}
"tag5678": {
tagName: tasmanian wolf
}

Redux data structuring

I'm trying to build a complex fully-dynamic app with Redux. I mean my App has lots of dynamic-generated forms with generated fields-components on-the-fly. I want to store in my Redux-store visual data about my components too. But how should i do it without mixing real data with visual component data?
For example if i have structure like this
Store {
visual: {...deeply nested visual-data-tree...},
data: {...deeply-nested real-data-tree...}
}
It is hard to render component because i need to search visual data first, then react component "value" in two trees.
But if have a structure similar to this:
Store {
form {
visual: {...form visual data...},
data: {
//Ok here the form "data" - widgets. Or it must to be visual? :)
widget1 {
visual: {type:"ComboBox", opened: true},
data: 1
}
}
}
}
You see the problem, now i have visual data inside real data of Form widget.
(form - data - widget1 - visual)
Visual data inside the real data is out of the concept.
How do you guys solve same problems of mixing data?
Really sorry for my poor english. I hope i clearly explained the problem.
Isn't the distinction superficial? I think a more important rule is that the data in the state should be normalized. For example, if you have Combobox widget letting you choose users, your data shape better be
{
chosenUserId: 10, // Good!
users: {
10: { name: 'Alice' }
}
rather than
{
chosenUser: { name: 'Alice' }, // Bad!
users: {
10: { name: 'Alice' }
}
If the data is duplicated in the state tree, it's hard to update it correctly and avoid inconsistencies.
As long as you keep the data normalized, I see no real need to divide visual and data. You might want to have top-level entity cache that looks like a database (e.g. entities which includes users, posts, or whatever data objects your app uses), but other than that, go with whatever state shape feels most comfortable when retrieving the relevant state.

Foreign key conditions in sailsjs Waterline ORM

I have defined two models like below, what i need to do is to retrieve the unique neighborhoods that belong to active partners (partner.status=1), i can retrieve the grouped neighborhoods like this
Locations.find({groupBy: [ 'neighborhood' ],sum['id']}, function(err,locations){});
and then match against a retrieved list of active Partners or backwards (ie first getting the active partners with the locations for each partner and pushing them to an array after verifying they are not already in there) or just by a custom sql query (which i am trying to stay away from)
but... i want to know if there is some kind of way to do it with the ORM as i have seen model.find().populate('model') doesn't accept parameters beyond the desired model not the where in the find method accept foreign keys conditions.
Partner:{
attributes:{
businessName:{
type:'string'
},
status:{
type:'INT'
}
locations:{
model:'Locations'
via:'partner_id'
}
}
}
Locations:{
attributes:{
partner_id:{
model:'Partners',
type:'INT'
},
neighborhood:{
type:'STRING'
}
}
}
Thanks in advance!
Is this what you looking for?
Locations.find({where: {value1: key1}})
.populate('partners', {where: {value2: key2}})
.exec(function(err, locations){
// Now you've got what you need
});
P/S: Please checkout SailsJS v0.10.x documentation on GitHub. Personally I use this: https://github.com/balderdashy/sails-docs/tree/0.10
The documents are not up-to-date though :-)

Categories