When first building my app, I had manually created data and it looked similar to this:
{
"data": {
0: {
"author": "gracehop",
"title": "Announcing COBOL, a New Programming Language"
},
1: {
"author": "alanisawesome",
"title": "The Turing Machine"
}
}
}
I could retrieve the data using core-ajax and iterate through a custom component without problem, like this:
<template is="auto-binding">
<core-ajax id="ds" auto url="https://mysite.firebaseio.com/data.json" response="{{data}}"></core-ajax>
<my-items items="{{data}}"></my-items>
</template>
However, now I'm attempting to create new data in my app using push(). The problem is that the new data looks like this:
{
"data": {
"-JRHTHaIs-jNPLXOQivY": {
"author": "gracehop",
"title": "Announcing COBOL, a New Programming Language"
},
"-JRHTHaKuITFIhnj02kE": {
"author": "alanisawesome",
"title": "The Turing Machine"
}
}
}
This lines up with their documentation, which states
Your first instinct might be to use set() to store children with
auto-incrementing integer indexes ... Firebase provides a push()
function that generates a unique ID every time a new child is added to
the specified Firebase reference. By using unique child names for each
new element in the list, several clients can add children to the same
location at the same time without worrying about write conflicts. The
unique ID generated by push() is based on a timestamp, so list items
will automatically be ordered chronologically.
After pushing an item or two, I no longer see any items in my list. If I delete anything created using push() the other items show up again.
Instead of using the core-ajax element, you should be using the native firebase-element. You can then connect it with your data by assigning the location attribute to your unique Firebase URL, then access the data with the data attribute. Likewise, if you are interested in looping through your data, you will need to access the keys attribute since Polymer currently only iterates through arrays.
Your firebase element would look something like this:
<firebase-element id="base" location="https://YOUR.firebaseio.com/"
data="{{data}}" keys="{{keys}}"></firebase-element>
You would then access it like so:
<template repeat="key in keys">
<p>This is your uniqueId generated keys: {{keys}}</p>
<p>This is the data in the keys: {{data[key]['author']}}</p>
</template>
Here is the ref: http://polymer.github.io/firebase-element/components/firebase-element/
The items are not missing or deleted. Indeed if you check out your account dashboard, you'll see both the numeric indices and the push ids. What happens is related to Firebase's handling of array-like data. (You'll want to give that a serious read to understand this)
Essentially, since you've used sequential, numeric ids, the data is treated as an array and returned as an array. But when you add a string as a key, it decides this is now a hash of key/value pairs and treats it as pojo/json data (rightly so).
I don't know much (anything) about Polymer, but I'm guessing that method accepts an array and does not iterate object keys. Thus, you'll need to iterate that data as an object and not an array.
Related
I've created an SNS topic, and I'd like to subscribe to it with a filter policy that matches a nested attribute. For example, given a message like this:
{
"foo": {
"bar": "baz"
},
"quux": "vorp"
}
I'd like to match only messages where the bar attribute of foo is equal to baz.
The documentation I've found so far only mentions matching attributes specified at the top level. I'm interested in a nested attribute. For the purposes of this question, let's assume I don't control the structure of the message.
Subscription filters don't act on the message (body, payload). They only act on the message attributes.
Message attributes are not complex objects... their only types are string, string array, number, and binary. If a message attribute contains a serialized object (e.g. JSON), subscription filters aren't designed to support extracting/matching the serialized data inside.
As of 2022, it's possible to filter based on the payload.
That's mentioned here:
https://docs.aws.amazon.com/sns/latest/dg/sns-message-filtering.html
An Example of filtering:
Let's say your original message is like:
{
"eventType": "SOME_STRING",
"otherAttribs": "bla..."
}
Then the filter can be something like:
{
"eventType": [
{
"prefix": "SAMETH"
}
]
}
In AWS WebConsole, it's found in SNS -> Subscriptions -> [select one] -> Subscription filter policy.
Now, SNS can filter events based on their payload as well. With this release, the SNS filter policy can handle property nesting too. For more information, please take a look at: https://aws.amazon.com/blogs/compute/introducing-payload-based-message-filtering-for-amazon-sns/
I need to update a field in a nested object with a dynamic key.
the path could look like this: level1.level2.DYNAMIC_KEY : updatedValue
The update-method deletes everything else on level1 instead of only updating the field in the nested object. The update() acts more like a set(). What am I doing wrong?
I tried the following already:
I read the documentation https://firebase.google.com/docs/firestore/manage-data/add-data#update-data
but that way it is a) static and b) still deletes the other fields.
Update fields in nested objects
If your document contains nested objects, you can use "dot notation" to reference nested fields within the document when you call update()
This would be static and result in
update({
'level1.level2.STATIC_KEY' : 'updatedValue'
});
Then I found this answer https://stackoverflow.com/a/47296152/5552695
which helped me to make the updatepath dynamic.
The desired solution after this could look like
field[`level1.level2.${DYNAMIC_KEY}`] = updateValue;
update(field);
But still: it'll delete the other fields in this path.
UPDATE:
The Structure of my Doc is as follows:
So inside this structure i want to update only complexArray > 0 > innerObject > age
Writing the above path into the update() method will delete everything else on the complexArray-level.
A simple update on first-level-fields works fine and lets the other first-level-fields untouched.
Is it possible, that firestore functions like update() can only act on the lowest field-level on an document. And as soon as i put complex objects into an document its not possible to select such inner fields?
I know there would be the solution to extract those "complex" objects into separate collections + documents and put these into my current lowest document level. I think this would be a more accurate way to stick to the FireStore principles. But on Application side it is easier to work with complex object than to always dig deeper in firestore collection + document structure.
So my current solution is to send the whole complex object into the update() method even though I just changed only one field on application side.
Have you tried using the { merge: true } option in your request?
db
.collection("myCollection")
.doc("myDoc")
.set(
{
level1: { level2: { myField: "myValue" } }
},
{ merge: true }
)
I have a restaurant bookmarks list in my firebase, but I don't know how to delete a specific restaurant in my database.
So I have the function unfavorite(favorite) where I pass the favorite restaurant as a parameter. Till here, than I want to pass this parameters id to the query to remove from the database like this:
this.afDb.list(`bookmarks/${user.uid}/restaurant/${favorite.restaurant.id})`).remove();
here is a screenshot of my database list:
How can I remove that specific restaurant out of the bookmarks list?
You will first need to add an ".indexOn": ["id"] rule to your database something like this:
"bookmarks": {
"$user_id": {
// normal reads and write rules here
},
".indexOn": ["id"]
This step is necessary for firebase database because otherwise you wont be able to use the orderByChild() and equalTo() methods.
Then, where you have your delete function, you want to instead use:
exampleRef = yourDb.ref("bookmarks/${user.uid}"); //this is just to simplify your reference a bit
exampleRef.orderByChild('id').equalTo(theDeleteIDhere).once('value').then(snapshot => {
snapshot.forEach((restaurant) => {
restaurant.ref.remove();
});
}); //this is a Promise that you can modify to return "true" if successful for example
The example I provided is just the way I have done it before (i.e. I prefer to use promises; hence the then() becuase this makes it easier to return that promise in an angular service which allows me to check whether the request was successful). You can use any variation of this so long as you have the "indexOn" rule and you use any sort of "sorting" method firebase provides here
Method 2
When I wrote this I totally glanced over the ability to map your restaurants like such:
Lets say your project is already listing those restaurants. You can therefore save each restaurant's auto generated id to a variable or map:
restaurants; // this is a map like this <your-identifier:autoID>
you can then easily just call:
exampleRef.child(restaurants[yourIdentifier]).remove();
I'm working on a game. Originally, the user was in a single dungeon, with properties:
// state
{
health: 95,
creatures: [ {}, {} ],
bigBoss: {},
lightIsOn: true,
goldReward: 54,
// .. you get the idea
}
Now there are many kingdoms, and many dungeons, and we may want to fetch this data asynchronously.
Is it better to represent that deeply-nested structure in the user's state, effectively caching all the other possible dungeons when they are loaded, and every time we want to update a property (e.g. action TURN_ON_LIGHT) we need to find exactly which dungeons we're talking about, or to update the top-level properties every time we move to a new dungeon?
The state below shows nesting. Most of the information is irrelevant to my presentational objects and actions, they only care about the one dungeon the user is currently in.
// state with nesting
{
health: 95,
kingdom: 0,
dungeon: 1,
kingdoms: [
{
dungeons: [
{
creatures: [ {}, {} ],
bigBoss: {},
lightIsOn: true,
goldReward: 54
}
{
creatures: [ {}, {}, {} ],
bigBoss: {},
lightIsOn: false,
goldReward: 79
}
{
//...
}
]
}
{
// ...
}
]
}
One of the things that's holding me back is that all the clean reducers, which previously could just take an action like TURN_ON_LIGHT and update the top-level property lightIsOn, allowing for very straight-forward reducer composition, now have to reach into the state and update the correct property depending on the kingdom and dungeon that we are currently in. Is there a nice way of composing the reducers that would keep this clean?
The recommended approach for dealing with nested or relational data in Redux is to normalize it, similar to how you would structure a database. Use objects with IDs as keys and the items as values to allow direct lookup by IDs, use arrays of IDs to indicate ordering, and any other part of your state that needs to reference an item should just store the ID, not the item itself. This keeps your state flatter and makes it more straightforward to update a given item.
As part of this, you can use multiple levels of connected components in your UI. One typical technique with Redux is to have a connected parent component that retrieves the IDs of multiple items, and renders <SomeConnectedChild itemID={itemID} /> for each ID. That connected child would then look up its own data using that ID, and pass the data to any presentational children below it. Actions dispatched from that subtree would reference the item's ID, and the reducers would be able to update the correct normalized item entry based on that.
The Redux FAQ has further discussion on this topic: http://redux.js.org/docs/FAQ.html#organizing-state-nested-data . Some of the articles on Redux performance at https://github.com/markerikson/react-redux-links/blob/master/react-performance.md#redux-performance describe the "pass an ID" approach, and https://medium.com/#adamrackis/querying-a-redux-store-37db8c7f3b0f is a good reference as well. Finally, I just gave an example of what a normalized state might look like over at https://github.com/reactjs/redux/issues/1824#issuecomment-228609501.
edit:
As a follow-up, I recently added a new section to the Redux docs, on the topic of "Structuring Reducers". In particular, this section includes chapters on "Normalizing State Shape" and "Updating Normalized Data".
Is there a way to filter down which properties of each child I want to bring back inside of ref.on("value", ...)?
Let's say I have the structure on https://www.firebase.com/docs/data-structure.html, but in addition to name, each user also has a list of every line of chat he has produced. How can I bring back only the name?
UPDATE: As of Firebase 2.0, you can now query based on fields.
There isn't currently a way to pick data out of a path (i.e. filter which fields you get back). The easiest solution here is to store the data in different paths. It greatly simplifies the process.
users/
users/names/fred/first
users/chat_history/fred/...
Another useful approach, particularly when you're going to be using a lot of subsets (e.g. friends list, members of a group, et al) is to use an index.
user_index/group_1/fred
user_index/group_1/mary
user_index/group_2/...
users/fred/name
users/fred/chat_history
Then you can access the data with something like this:
var fb = new Firebase(INSTANCE);
fb.child('user_index').on('child_added', function(ss) {
fb.child('users/'+ss.name()+'/name').once('value', function(nameSnapshot) {
var userName = nameSnapshot.val();
});
});