Firebase database().ref() nonexistent path - firebase

In firebase, my app will be creating nested data all the time. My question is do I first have to check if a key exists before i can reference it, or can i just...
const ref = firebase.database().ref("dataTree/" + childVar1 + "/" + childVar2);
ref.push({data: "this is data"});
and it will create the nested structure for me? i.e. :
{
"dataTree": {
"notChildVar1": {
"someChildName": {
"data": "test"
}
}
"alsoNotChildVar1": {
"someChildName": {
"data": "test"
}
}
}
}
Should Become...
{
"dataTree": {
"notChildVar1": {
"someChildName": {
"data": "test"
}
}
"alsoNotChildVar1": {
"someChildName": {
"data": "test"
}
}
"childVar1": {
"childVar2": {
"data": "test"
}
}
}
}
And if the above code will return an error, what can i do to test if a key exists, add it if it does not exist, and then push something in that?

Maybe you can try something like create the full content of childVar1 and insert directly in your database including the childVar2: {data: test} (I supposed that you're using RealtimeDatabase).
const ref = firebase.database().ref("dataTree/" + childVar1);
ref.push(
"childVar2": {
"data": "this is data"
}
);

You can write to any arbitrary location in the database, and any required nodes that do not exist will be created for you automatically. You don't have to create each child node individually.
Similarly, if all children of a node are deleted, the node itself will be deleted automatically (there is no such thing as an "empty" child node).

Related

How Haetoas conform add Links

I want to add links to some related entities and collection, without all property data in one response, only the Link.
For unterstanding I structure the Question in some parts
Simple example of data Model
Order
Order->AddressFrom (Entity)
Order->PackageItems (Collection)
Which is the wright HAETOAS way to generate links or how to name entities in response.
First question: How to link address, double in entity name and links part and how to nam?
{
"_embedded":{
"orders":[
{
"id":"id",
"addressLinkFrom":{
"href":"link"
},
"_links":{
"self":{
"href":"link"
},
"addressFrom":{
"href":"d"
}
}
}
]
}
}
or
"addressFrom":{
"href":"link"
},
"_links":{
...
}
or
or
"addressFrom":{
"self":{
"href":"link"
}
},
"_links":{
...
}
Second: How to link collection to specific and not all entities
{
"_embedded":{
"orders":[
{
"id":"id",
"packageItemIds":[
{
"href":"link"
},
{
"href":"link"
}
]
}
]
}
}
or
"packageItemIds":[
{
"self:"{
"href":"link"
}
}]
Third: How is the right format for (update, post), which I have to parse, like the address, where I'm sending the ID or like the packageItems, where I sending the link.
{
"id":"id",
"addressFrom":{
"id":"12345"
}
"packageItems":[
{
"href":"link"
},
{
"href":"link"
}
]
}
For your information, as frontend Client I'm using lagoshny /
ngx-hateoas-client,
when someone has their extra information beside the HAETOAS standard, how is the best way, please tell me.
Thanks for your help.I want to add links to some related entities and collection, without all data in one response.

Flatten Apollo response from WpGraphql in next.js

I'm trying to change the result that apollo returns with the data on the client side. I've read in the docs of version 3 that maybe this is possible. I currently have a graphql query that returns data within an EDGES array, and then each item is in a "node" before you get to the actual data.
The query looks like:
export const QUERY_ALL_POSTS = gql`
query AllPosts {
posts(first: 20) {
__typename
edges {
__typename
node {
__typename
author {
node {
avatar {
height
url
width
}
id
name
slug
}
}
id
categories {
edges {
node {
databaseId
id
name
slug
}
}
}
content
date
excerpt
featuredImage {
node {
altText
caption
sourceUrl
srcSet
sizes
id
}
}
modified
databaseId
title
slug
isSticky
}
}
}
}
`;
And the response looks like:
I know that I can write the typePolicy this way to change the date string for example:
Post:{
fields:{
date(){
return 'date edit'
}
}
},
So I wanted to see if I could change the response of the entire array that gets returned to something like this because I'll be needing to check for edges and nodes in every component which is kinda of annoying:
posts:[
{...item 1},
{...item 2},
{...item 3},
...etc
]
I've tried to write a typePolicy like this, and it returns the correct data, but when I query it on the frontend, nothing has changed. The data is still contained in an Edges object and each item is still in a NODE from the wpGraphql backend.
typePolicies: {
Post:{
fields:{
date(){
return 'date edit test' // returns a modified date object
}
}
},
Query: {
fields: {
// posts: flatten(),
posts:{
read(posts, { readField }) {
if(posts){
const newItem = posts.edges.map(post => {
return post.node
})
console.log('newItem', newItem)
return newItem
}
return posts // does not return a modified posts object
},
}
},
},
},
Can I modify the response like this or do I just have to write a custom helper function to modify the data every time I query it before using the data inside a component?

How to apply a Hasura `where` filter only if a variable is not null?

I have a query like this:
query getUsers ($setId: Int) {
user(where: { user_sets: { set_id: { _in: [$setId] } } }) {
id
name
status
user_sets {
set {
name
}
}
# more fields...
}
}
What I'm looking for, is a way to not apply the where filter and give all entries if $setId is null. I'd like to avoid dynamically writing the query - it'd be easy to do something like this, but we want queries in static .graphql files:
const query = `
query getUsers (${ setId ? '$setId: Int' : ''}) {
user(${ setId ? 'where: { user_sets: { set_id: { _in: [$setId] } } }' : '' }) {
`
Some things I've tried:
Using GraphQL directives like #skip and #include, but it seems these only apply to fields returned, not to any part of a where filter
Using Hasura boolExps like _is_null and _or, but it seems these can't test variables directly, they can only compare variables to columns contents
This behaviour changed somewhere between v1.3.4. Therefore there are two correct answers.
You can read more about this change in the hasura repository.
Before Version 1.3.4
This answer describes it.
After Version 1.3.4
Using null in comparisons is dangerous when defaulting to true because an accidentally unset variable could result in a dropped table. The maintainers removed this behaviour but made it accessible by setting the variable HASURA_GRAPHQL_V1_BOOLEAN_NULL_COLLAPSE.
When comparing with {_eq: null}, Hasura will throw an error because it is assumed that this is a mistake.
If you want to compare to a value and evaluate to true when the value is null, you need to handle the case on the client side and pass the whole boolean expression to Hasura.
query getUsers ($userSetsWhere: user_sets_bool_exp) {
user(where: { user_sets: { $userSetsWhere } }) {
id
name
status
user_sets {
set {
name
}
}
# more fields...
}
}
const userSetsWhere = setId ? { set_id: { _eq: $setId } } : {};
What it does, is that only in case the value is not null or undefined a non-empty expression gets passed to Hasura.
You can use bool expressions as binding variables for such situations
query getUsers ($condition: user_bool_exp!) {
user (where: $condition) {
id
name
status
user_sets {
set {
name
}
}
# more fields...
}
}
And you can build conditions depending on your variables
{ condition: { user_sets: { set_id: { _in: [$setId] } } } }
or
{ condition: { user_sets: {} }
This answer only applies to Hasura v1.X, see other answers for more recent versions.
It seems like matching all if the variable is null is the default behaviour if the _eq boolExp is used. I wasn't seeing this because this query was using _in.
Changing to this gives all items if $setId is passed as null:
query getUsers ($setId: Int) {
user(where: { user_sets: { set_id: { _eq: $setId } } }) {
id
name
status
user_sets {
set {
name
}
}
# more fields...
}
}
This is because Hasura follows SQL by having null not comparable to anything (only _is_null can match values that are set as null in nullable columns).
Therefore, { _eq: null } logically can't match anything, so it's simply optimised away. This:
(where: { user_sets: { set_id: { _eq: $setId } } })
...becomes this:
(where: { user_sets: { set_id: {} } }
...and because {} is trueExp, treated as true, it optimises away to be effectively WHERE 'true'.

When querying for a single item in graphql, meteor, and apollo i get null values returned

I have probably overlooked something in the docs, but I have seem to run into a problem with being able to get a single object from my graphql queries.
Here is the schema:
type Query {
product(name: String!): Product
}
type Product {
_id: String
name: String
}
Here is the resolver:
Query: {
product (_, args) {
return Products.find({where: args})
},
products () {
return Products.find().fetch()
}
}
Here is the Query:
query {
product(name: "burgers") {
name
}
}
I get a result of this:
{
"data": {
"product": {
"name": null
}
}
}
Am I just forgetting to add something to this, and if so could you point me the right direction.
If Products is a Meteor Collection, then .find returns a cursor, so the right thing to return would be Products.findOne({name: args.name})
http://docs.meteor.com/api/collections.html#Mongo-Collection-findOne

Difficulty setting up validation rules for Firebase datastructure

I'm working on setting up validaton rules for a Firebase data structure, created using the Bolt compiler.
I'm currently having the Bolt statement below:
path /sharedEvents/{share} is Boolean[] {
read() { isMailOfCurrentUser( share ) }
create() { isOwnerOfEvent( ...) } //NOT YET CORRECT!
delete() { isOwnerOfEvent( prior(...) } //NOT YET CORRECT!
}
With this, I'm trying to achieve that:
Only users having a mail corresponding to the key of 'share' are allowed to read the data (they use this date to retrieve the key of events shared with them.
Only the owner of an event is able to add/remove the key for his event to the list of shared events.
This second point is where I'm running into trouble -I'm not able to create the create/delete rules- since I have no idea how to reference the keys of the boolean values in the validation rule...
Example data in Firebase for the above bolt statement:
sharedEvents
ZW5kc3dhc0BldmVyeW1hMWwuYml6
-BDKBEvy-hssDhKqVF5w: true
-FDKBEvy-hsDsgsdsf5w: true
-ADBEvy-hfsdsdKqVF5w: true
aXQnc251bWJlcnNAbWExbDJ1LnVz
-KBEvy-hsDhH6OKqVF5w: true
To clarify the needs on this example:
Only user with mail 'ZW5kc3dhc0BldmVyeW1hMWwuYml6' is able to read the three nested childs.
Only the owner of event '-BDKBEvy-hssDhKqVF5w' should be able to create/delete this value. (the same for the other event key/boolean pairs).
My question: is this setup going to work (and how to setup the create/delete rules)? Or is this not going to work and should I rethink/structure the data?
Any help is appreciated!
-----------------OUTPUT JSON FILE------------------------------------------
The question above has been answered, this section is showing the resulting json
"sharedEvents": {
"$share": {
".read": "<removed for readability>",
"$event": {
".validate": "newData.isBoolean()",
".write": "<removed for readability>"
}
}
},
Thanks again for your quick support!
You'll need a nested path statement to handle the restriction on the events (the nodes under /sharedEvents/$mail/$eventid). I quickly prototyped with this JSON structure:
{
"events": {
"-ADBEvy-hfsdsdKqVF5w": {
"name": "Event 1",
"ownerMail": "aXQnc251bWJlcnNAbWExbDJ1LnVz"
},
"-BDKBEvy-hssDhKqVF5w": {
"name": "Event 2",
"ownerMail": "aXQnc251bWJlcnNAbWExbDJ1LnVz"
},
"-FDKBEvy-hsDsgsdsf5w": {
"name": "Event 3",
"ownerMail": "aXQnc251bWJlcnNAbWExbDJ1LnVz"
},
"-KBEvy-hsDhH6OKqVF5w": {
"name": "Event 3",
"ownerMail": "ZW5kc3dhc0BldmVyeW1hMWwuYml6"
}
},
"sharedEvents": {
"ZW5kc3dhc0BldmVyeW1hMWwuYml6": {
"-ADBEvy-hfsdsdKqVF5w": true,
"-BDKBEvy-hssDhKqVF5w": true,
"-FDKBEvy-hsDsgsdsf5w": true
},
"aXQnc251bWJlcnNAbWExbDJ1LnVz": {
"-KBEvy-hsDhH6OKqVF5w": true
}
},
"userMails": {
"peter": "aXQnc251bWJlcnNAbWExbDJ1LnVz",
"puf": "ZW5kc3dhc0BldmVyeW1hMWwuYml6"
}
}
And came up with these rules:
path /sharedEvents/{share} {
read() { isMailOfCurrentUser(share) }
}
path /sharedEvents/{share}/{event} is Boolean {
create() { isOwnerOfEvent(event) }
delete() { isOwnerOfEvent(prior(event)) }
}
isMailOfCurrentUser(share) { true }
getMailOfCurrentUser(uid) { root.ownerMails.uid }
getEventOwnerMail(event) { root.events.event.ownerMail }
isOwnerOfEvent(event) { getMailOfCurrentUser(auth.uid) == getEventOwnerMail(event) }
Ignoring any mistakes on my end, this should be the basics of the authorization structure you're looking for.

Resources