This question already has answers here:
Firebase DB - How to update particular value of child in Firebase Database
(3 answers)
Closed 4 years ago.
I am trying to keep some data consistent with firebase cloud functions. When data changes in the main list, I want all the data to change in the user's favourite list.
Currently, I am able to call the function and get a log of the correct data which is changing, but my query doesn't work. I am getting the following error:
TypeError: ref.update is not a function
at exports.itemUpdate.functions.database.ref.onUpdate
Here is my code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.itemUpdate = functions.database
.ref('/items/{itemId}')
.onUpdate((change, context) => {
const before = change.before.val(); // DataSnapshot after the change
const after = change.after.val(); // DataSnapshot after the change
console.log(after);
if (before.effects === after.effects) {
console.log('effects didnt change')
return null;
}
const ref = admin.database().ref('users')
.orderByChild('likedItems')
.equalTo(before.title);
console.log(ref);
return ref.update(after);
});
I'm not to sure where I am going wrong, I appreciate all the help and guidance to resolve this!
Cheers.
equalTo() returns a Query object. You're then trying to call update() on that object. Note that in the linked API docs, Query doesn't have an update() method. You can't simply "update" a Query that hasn't been performed. You're going to have to actually perform the query using once(), iterate the results form the snapshot in the returned promise, and perform further updates using the data you find.
Related
I posted a question earlier about how to query for a specific value inside an array. I was told that there was a similar question already asked. I have looked at the solution for that question however i am getting an error. This is my code currently to check to see if the field mal_id inside the favourites array contains an id passed by me.
const docRef = collection(db, 'users')
const q = query(docRef, where('favourites', 'array-contains', {mal_id: id}))
I then attached an onSnapshot method to see if the data exists which is like this
onSnapshot(q, (snapshot) => {
if(snapshot.data()){
console.log(true)
}
else{
console.log(false)
}
})
But i get an error saying snapshot.data is not a function. idk if you are not supposed to use an onSnapshot method on this kind of query or my code is wrong. I have attached a picture of my database structure. Thanks.
*Edit
So, i have changed my data structure. Now i am creating a new field called animeID and then storing the id into it. I then do the array contains onto that but the snapshot still gives me the same error. Here is the updated code along with a new picture of my database structure.
const docRef = collection(db, 'users')
const q = query(docRef, where('animeID', 'array-contains', `mal_id: ${id}`))
onSnapshot(q, (snapshot) => {
if(snapshot.data()){
console.log(true)
}
else{
console.log(false)
}
})
Updated firestore structure
As Doug commented, Firestore's array-contains operator checks for equivalence between the value you supply and an entire array item. It can't find a subset of an item.
The common workaround is to add an additional field to your document with just the mal_id values you want query on. So something like:
Favourites_mal_ids: [21]
And then you can perform an array-contains on that field.
Given the following data struct in firebase, I wish to retrieve the field in just standard JS. I have tried many methods of getting it, but for some reason, I cannot. I have tried .get(), forEach(), I have tried getting a snapshop, but it won't work.
At the start of my JS file I do:
const auth = firebase.auth();
const db = firebase.firestore();
let totalGroups;
db.collection('totalGroups').doc('totalGroups').get().then(function(querySnapshot) {
querySnapshot.docs.forEach(function(doc) {
if (doc.data().totalGroups != null) {
totalGroups = doc.data().totalGroups console.log("here is total groups" + totalGroups)
//Total Groups is undefined out here but defined in fuction
}
})
})
and normally I am able to get .get() just fine. I am looking for the most simple method of getting this value. thanks.
First, you are using get() on a DocumentReference which returns a DocumentSnapshot containing data of that single document only and has no docs property on it. Try refactoring the code as shown below:
db.collection('totalGroups').doc('totalGroups').get().then(function(snapshot) {
const docData = snapshot.data();
console.log(docData)
})
Also do note that if you were using get() on a CollectionReference, then it would have returned a QuerySnapshot where the existing code works fine.
I am following the Firebase tutorial on how to implement Algolia with Firebase: https://firebase.google.com/docs/firestore/solutions/search
I am currently stuck on the indexing part of the tutorial as I have errors coming from the firebase cloud-functions logs.
This is the output of the cloud-functions log
and this is the code I wrote
const functions = require('firebase-functions');
const algoliasearch = require("algoliasearch");
const ALGOLIA_ID = functions.config().algolia.app;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.key;
const ALGOLIA_SEARCH_KEY = functions.config().algolia.search_key;
const ALGOLIA_INDEX_NAME = 'users';
const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);
// Update the search index every time a blog post is written.
exports.onUserCreated = functions.firestore.document('organisations/40R0LMA6ALZgF7KjHJMc/employees/{userId}').onCreate((snap, context) => {
// Get the note document
const user = snap.data();
// Add an 'objectID' field which Algolia requires
user.objectID = snap.id;
console.log(user.objectID)
// Write to the algolia index
const index = client.initIndex(ALGOLIA_INDEX_NAME);
return index.saveObject(user);
});
It seems that you are not correctly setting the different environment variables used in this example.
As explained in the doc, to get the value of the algolia.app environment variable when you do const ALGOLIA_ID = functions.config().algolia.app; you need to previously set its value as follows:
firebase functions:config:set algolia.app="THE_ALGOLIA_ID"
Since you need to set several variables, you can set them in one instruction, as follows:
firebase functions:config:set algolia.app="THE_ALGOLIA_ID" algolia.key="THE_ALGOLIA_ADMIN_KEY" ...
As explained in the doc, "to inspect what's currently stored in environment config for your project, you can use firebase functions:config:get" in the CLI.
Every hour, I want my firebase function to look through my database, read a value, calculate a new value from this old value, and then update it in the database. I am having trouble accessing a snapshot of the data. Specificically,
exports.scheduledFunction = functions.pubsub.schedule('every 1 hour').onRun((context) => {
const ref = functions.database.ref('/users/test_user/commutes');
ref.once('value',function(snapshot) {
// do new calculation here
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
return null;
});
I am getting a : functions: TypeError: ref.once is not a function error.
How do I access a value from my firebase real time database and update it from a Firebase function?
You're trying to use the firebase-functions SDK to query the database. It can't do that. You will have to use the Firebase Admin SDK to make the query.
You will need to get started like this (not complete, but you should be able to see what you need to do). Import and initialize at the global scope:
const admin = require('firebase-admin')
admin.initializeApp()
Then in your function, use it. Be sure to work with promises correctly.
const ref = admin.database().ref('...')
return ref.once('value').then(snapshot => {
// work with the snapshot here, and return another promise
// that resolves after all your updates are complete
})
The firebase-functions is different from the client side. The ref() function according to the docs:
ref: function
ref(path: string): RefBuilder
Select Firebase Realtime Database Reference to listen to.
Path of the database to listen to.
Returns RefBuilder
The RefBuilder will contain the database triggers that you can call, onCreate(), onWrite(). To be able to use your database, then you need to use the admin sdk.
https://firebase.google.com/docs/reference/functions/providers_database_.refbuilder
I get this error in the Cloud Firestore Function log view.
I'm new to JavaScript and Firestore and could use some advice on this
TypeError: event.data.previous.data is not a function at
exports.onVisitorPres...
exports.onVisitorPresenceWrite = functions.database
.ref("/VISITORS_PRESENCE/{uid1}/{uid2}").onWrite((event) => {
// Get the data written or deleted on the Realtime Database
var eventStatus = event.data.val();
const previousData = event.data.previous.data();
// If the onWrite event is a delete event then use previousData
if(eventStatus == null){
eventStatus = previousData;
}
});
What I want to do is using the .onWrite((event) on a Firebase Realtime databas key and Firestore Function trigger when the key items get deleted and when new items are added.
I thought I could check the eventStatus == null and that is when data is deleted I simply use the previousData (before it got delete??)
The event variable is an instance of Event and therefore calling event.data will return a DeltaDocumentSnapshot for Firestore and a DeltaSnapshot for the Realtime Database.
With a these delta snapshots, you can obtain the previous value with previous which will return another DeltaDocumentSnapshot or DeltaSnapshot containing the previous state from before the write event was triggered.
In your example, you're using a Firebase Realtime Database trigger, which means event.data.previous will return a DeltaSnapshot, which does not support data(), but instead supports val().
In this case, as you've done with var eventStatus = event.data.val();, you need to call val() on previous:
const previousData = event.data.previous.val();
If instead you are trying to use a Firestore trigger, you need to change this:
functions.database.ref("[...]")
To this:
functions.firestore.document("[...]")
And then you can use event.data.previous.data().