I have my firebase app working with React whereby I sign users up and then log there information to the database. I am creating a "dating app" and I would like some way to store empty arrays. e.g, matchers: [] etc
I tried something liket this:
firebase.database().ref('users/' + userId).set({
id: userId,
username: name,
email: email,
matchers: [],
likedUsers: [],
disLikedUsers: []
});
but then read that firebase doesn't really handle arrays as such and now am not sure how to do this. I want the empty array so then when the user starts using the app they can add to their various arrays.
any ideas?
Firebase has always recommended against using arrays. Instead of re-iterating the reasons, I'll point you to the blog post Best Practices: Arrays in Firebase.
But your bigger problem seems to be having empty arrays: the . If a property doesn't have a value, the Firebase Database doesn't store that property. That means that an empty array is not stored in the database and thus not read back.
You'll have to re-create those properties yourself after you read the data back. If you're having problems with this, update your question to show how you read the data.
You don't need to create those fields, they are initialized with the first item and the recommended way to indexed collections is to use the push and later to map it to an array.
Related
I have the following test data
1: {
match: "Game 1",
scorer: ["foo","bar"] //this could also be an object
}
My question is how do I correctly append new value to an array without overwriting it? My idea was to retrieve existing data then spread it like so [...currentData, "bob"]. Is there a better alternative?
const addScorer = (matchId) => {
return update(ref(db, path), {
scorer: ["bob"]
})
}
There is no atomic operation to add an item to an array directly in the database. This means you'll need to:
Read the array into your application code
Append the item to the array
Write the entire array back to the database
This is one of the many reasons why Firebase recommends against using arrays for lists of data, but instead has a push() operation that circumvents most problems. For more on this, see the link to the document that Nilesh included in their comment, or read this article on Best Practices: Arrays in Firebase.
So I'm working on a personal project to learn react-native and Firestore.
I have a DB like this:
And I want my code to add a new battery in the array batteries.
The elements in the array are just a map{string, string}
The problem is that when I update the array with a new brand that's work but if I want to update it with the same brand again have,
so having by the end
batteries[0]: {'brand': 'cestmoi'}
batteries[1]: {'brand': 'cestmoi'}
The DB doesn't update, doesn't have any error or so.
I don't understand why and I followed their tutorial. Here is my code:
async function addData(collection, doc, value) {
console.log(`Add data ${value.brand}`)
try {
const result = await firestore()
.collection(collection)
.doc(doc)
.set({
batteries: firestore.FieldValue.arrayUnion(value)
})
console.log(result);
return result;
} catch (error) {
return error;
}
}
I use try-catch by habit but I don't know if the then...catch is better or not.
As already #windowsill mentioned in his answer, there is no way you can add duplicate elements in an array using client-side code. If your application requires that, then you have to read the entire array, add the duplicates and then write the document back to Firestore.
However, if you want to update an existing element in an array of objects (maps) then you have to use arrayUnion with the entire object. If you want to understand the mechanism better, you can read the following article which is called:
How to update an array of objects in Firestore?
arrayUnion says that it "adds elements to an array but only elements not already present". Maybe it does a stringify or something to check equality and therefore doesn't add the new element. I think you'll have to 1. get the current list, 2. add your element, 3. set the batteries field to the updated list.
I have a firestore firebase database , in which I have a collection users
there is an array in the collection and in the array there is a map
in map there is a field qty.. I want to increment that qty value..
using increment doesnt help as the qty is inside a array index
db.collection("users").doc(checkId).update({
myCart: firebase.firestore.FieldValue.arrayUnion({
qty: firebase.firestore.FieldValue.increment(1),
}),
this is the error Output =>
Uncaught (in promise) FirebaseError: Function FieldValue.arrayUnion() called with invalid data. FieldValue.increment() can only be used with update() and set()
My answer below won't work, given that the qty is in an array. The only way to update an item in an array is to read the entire document, update the item in the array, and then write the entire array with the updated item back to the document.
An alternative would be to use a map instead of an array, and then update the qty using the approach outlined in my (old, and non-working) answer below 👇
You need to specify the full path to the field you're trying to update. So I think in your case, that'll be:
db.collection("users").doc(checkId).update({
"myCart.0.qty": firebase.firestore.FieldValue.increment(1)
}),
The field you want to update is embedded in an array. In this case, you can't use FieldValue.increment(), since it's not possible to call out an array element as a named field value.
What you'll have to do instead is read the entire document, modify the field in memory to contain what you want, and update the field back into the document. Also consider using a transaction for this if you need to update to be atomic.
(If the field wasn't part of an array, you could use FieldValue.increment().)
As of today (29-04-2020)... this is tested by me.
Suppose my data structure is like this:
collection: Users
Any document: say jdfhjksdhfw
It has a map like below
map name: UserPageVisits
map fields: field1,field2,field3 etc
Now we can increment the number field in the map like below:
mapname.field1 etc...
That is use the dot operator to access the fields inside the map just like you would do to an object of javascript.
JAVA Code (Android), update the field using transactions so they can complete atomically.
transaction.update(<documentreference object>,"UserPageVisits.field1",FieldValue.increment(1));
I have just pushed a version of my app which uses this concept and it's working.
Kudos !!
My Best Regards
Previous answers helped me as well, but dont forget about the "merge" property!!! Otherwise it will overwrite your entire array, losing other fields.
var myIndex = 0;
const userRef = db.collection('users').doc(checkId);
return userRef.update({
'myCart.${myIndex}.qty': admin.firestore.FieldValue.increment(1)
}, {
merge: true
});
If I have an array in my state:
state: {
users: []
},
And I have objects like:
{
id: 1,
name: "some cool name"
}
I add them to the store in a mutator like users.push(user);. How can I add it to the users array so instead of 0:{...} it ends up using the real id as key 1:{...}?
I know I could possible do something like users[user.id] = user but I think that will not be reactive in Vue.js
An array is probably the wrong data structure if you want to look them up by id. More likely you want an object, users: {}. An array would only really be appropriate if there are relatively few gaps between the ids.
To keep the values reactive you'd use Vue.set, https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats. So using your example it'd be:
Vue.set(users, user.id, user)
If you do decide to stick with an array then there are other options, https://v2.vuejs.org/v2/guide/list.html#Caveats, such as splice.
Loosely related reading on normalising data in Vuex: https://forum.vuejs.org/t/vuex-best-practices-for-complex-objects/10143
Update:
Based on your comments about needing both key-based lookup and filtering, my suggestion would be to store the values using an object and then create a getter or computed property for Object.values(users) when you need an array instead. Both getters and computed properties are cached so the overhead (which is pretty small anyway) will only be incurred when the users change. That array can then be filtered using filter.
Im kinda new in firebase. As a first step, I would like to set a post and get calls to my newly made database in firebase.
Firebase has a lot of native functions which allows me to get elements and push them to the db. However, I would prefer to use native get/post calls.
My post calls seem to work just fine, it properly stores an element in the db and returns 200 status.
When I enter to my DB in firebase, I can see that it posses following data:
entries:
-L1cxn3-rLgp7PsPwjV3
author: "Mark"
title: "Hello"
-L1cyaOQ4TUYd3m16VfT
autor: "Lily"
title: "Hi"
So as I said before, it stores correct data. But the structure is unknown for me. It's like a map or an object.
I would like to ask you for help, how to properly retrieve it from get call.
The get call returns:
{"-L1cxn3-rLgp7PsPwjV3":{"author":"Mark","title":"Hello"},"-L1cyaOQ4TUYd3m16VfT":{"author":"Lily","title":"Hi"}};
I could take all keys from it Object.keys(data)
Then iterate over it to get it as an array -
Object.keys(data).map(r => data[r])
Now I would have an array of objects.
Is it a proper way to deal with it? Should I stay with my get/post calls or I should rather use firebase built-in functions? Thank u in advance! :)
Just use Object.values() if you want the array of objects
console.log(Object.values({"-L1cxn3-rLgp7PsPwjV3":{"author":"Mark","title":"Hello"},"-L1cyaOQ4TUYd3m16VfT":{"author":"Lily","title":"Hi"}}))