Cloud Functions for Firebase to index Firebase Database Objects in Algolia - javascript

I went through docs, github repositories but nothing worked for me yet.
My datastructure:
App {
posts : {
<post_keys> : {
auth_name : "name",
text : "some text" //and many other fields
}
}
}
1) Github repository : If I use this, I only get one field from one function, if I need all the fields, I would need to write separate functions for each, which is a bad approach.
2) Algolia Official Docs for Node.js : This cannot be deployed as a cloud function, but it does what I intend to do.
How can I write a function that can be deployed on Firebase and gets the whole object indexed with its key in Algolia?

Okay so I went ahead to create a Firebase Cloud function in order to index all objects in the Algolia index. This is the solution:
What you were doing is something like this:
exports.indexentry = functions.database.ref('/blog-posts/{blogid}/text').onWrite(event => {
What you should do is the following:
exports.indexentry = functions.database.ref('/blog-posts/{blogid}').onWrite(event => {
const index = client.initIndex(ALGOLIA_POSTS_INDEX_NAME);
var firebaseObject = event.data.val();
firebaseObject.objectID = event.params.blogid;
return index.saveObject(firebaseObject).then(
() => event.data.adminRef.parent.child('last_index_timestamp').set(
Date.parse(event.timestamp)));
});
The difference is in the first line: In the first case, you only listen to text changes, hence you only get the data containing the text change.
In the second case, you get the whole object since you listen to changes in all of the blog object (notice how /text was removed).
I tested it and it works for me: whole object including author was indexed in Algolia.

Related

How to get and set a ref for a newly cached related object in Apollo client InMemoryCache?

I have a set of related items like so:
book {
id
...
related_entity {
id
...
}
}
which apollo caches as two separate cache objects, where the related_entity field on book is a ref to an EntityNode object. This is fine, the related entity data is also used elsewhere outside of the context of a book so having it separate works, and everything seems well and good and updates as expected...except in the case where the related entity does not exist on the initial fetch (and thus the ref on the book object is null) and I create one later on.
I've tried adding an update function to the useMutation hook that creates the aforementioned related_entity per their documentation: https://www.apollographql.com/docs/react/caching/cache-interaction/#example-adding-an-item-to-a-list like this:
const [mutateEntity, _i] = useMutation(CREATE_OR_UPDATE_ENTITY,{
update(cache, {data}) {
cache.modify({
id: `BookNode:${bookId}`,
fields: {
relatedEntity(_i) {
const newEntityRef = cache.writeFragment({
fragment: gql`
fragment NewEntity on EntityNode {
id
...someOtherAttr
}`,
data: data.entityData
});
return newEntityRef;
}
}
})
}
});
but no matter what I seem to try, newEntityRef is always undefined, even though the new EntityNode is definitely in the cache and can be read just fine using the exact same fragment. I could give up and just force a refetch of the Book object, but the data is already right there.
Am I doing something wrong/is there a better way?
Barring that is there another way to get a ref for a cached object given you have its identifier?
It looks like this is actually an issue with apollo-cache-persist - I removed it and the code above functions as expected per the docs. It also looks like I could instead update to the new version under a different package name apollo3-cache-persist, but I ended up not needing cache persistence anyway.

Firebase: data gets removed immediately after pushing to realtime database

First time poster here!
While I was trying to build a little exercise organizer application with ReactJS and Firebase realtime database I encountered a problem with the Firebase push() method.
I have a couple elements on my page that push data to the database once they are clicked, which looks like this:
const planRef = firebase.database().ref("plan");
const currentExName = e.currentTarget.firstChild.textContent;
const exercise = {
name: currentExName,
type: e.currentTarget.children[1].textContent,
user: this.state.user.displayName
};
planRef.push(exercise);
Also, if the element is clicked again, then it gets removed from the database like this:
planRef.orderByKey().on("value", snapshot => {
let exercises = snapshot.val();
for (let ex in exercises) {
if (exercises[ex].name === currentExName) {
planRef.child(ex).set(null);
}
}
});
This is working fine as long as I don't try to push something to the database when I just deleted the last bit of data from it. In that case it gets removed right away.
Data getting removed
Summary:
Write data to the realtime database using ref.push()
Delete data using ref.child(child).set(null) (I tried remove() before, same problem)
Try to push the same data to the database again which leads to the data getting deleted right after being written to the database
I couldn't find anything about this kind of problem so far so I guess I might have made a mistake somewhere. Let me know if the information provided is not sufficient.
Thanks in advance.
Removing a child is an asynchronous operation. I guess what is happening here is the removing operation takes more time than the new writing operation. You will need to await for it if you want to write again on the same key.
planRef.child(ex).set(null).then(() => {
planRef.child(ex).push(new);
});
Or using async/await:
await planRef.child(ex).set(null);
planRef.child(ex).push(new);
Let me know if it worked.

Match value of array from database object in Firebase Cloud Functions

This is my first app project using Google Cloud Functions & Firebase. I'm trying to find away to get a single value of the array that I'm returning and compare it to a set variable and if it matches, update another child's value in that same account.
My App users can add records to the database under their login/user_id that is stored in the database. I'm trying to get a list of the "RecordName" that is a child under that login/user_id that every user has stored in their account.
So basically every "RecordName" in the entire database. When I want to run specials for those records, I need to match the name of that record to the name of the record I have on special and if there is a match, update another child value under that user's account ("special" = true.). This way, when they load their app next time, I have it highlighting that record so they know it's on special.
When I use..
const ref = admin.database().ref(`/store`);
...with the following code...
ref.on('value', function(snapshot) {
// puts ALL items of the object into array using function ..
console.log(snapshotToArray(snapshot));
});
... and the function...
function snapshotToArray(snapshot) {
var returnArr = [];
snapshot.forEach(function(childSnapshot) {
var item = childSnapshot.val();
item.key = childSnapshot.key;
returnArr.push(item);
});
return returnArr;
};
... I get the entire array just as it is in the database:
-store
-{ones_users_id}
-recordname: value1
-special: false
-{anothers_users_id}
-recordname: value2
-special: false
ect. ect.
If my record on special is called, "Newbie Record", what would be the best way to take out every individual value for the key: "recordname" from the array, compare each one to var = "Newbie Record" and if they match, update the value of the key: "special" to be true?
I'm new to JSON and NodeJS, I've been searching on here for answers and can't find exactly what I'm looking for. Your feedback would be very helpful.
It sounds like you're looking to query your database for nodes that have "recordname": "Newbie Record" and update them.
An easy way to do this:
const ref = admin.database().ref(`/store`);
const query = ref.orderByChild("recordname").equalTo("Newbie Record");
query.once('value', function(snapshot) {
snapshot.forEach(function(child) {
child.ref.update({ special: true })
});
});
Main differences with your code:
We now use a query to read just the nodes that we want to modify.
We now use once() to read the data only once.
We loop over the children of the snapshot, since a query may result in multiple nodes.
We use the reference of each child and then update its special property.
I recommend reading a bit more about Firebase queries in the documentation.

firebase cloud write data with a "key" paramter

I am learning Cloud Functions for Firebase. What I want is pass the key and value in the URL parameters, like:
https://xxx.cloudfunctions.net/addMessageSet?text=goodboy&key=testKey
And then in the Realtime Database set a testKey:goodboy.
I know use push() will generate a unique key (if i understood correctly) but I'd like use my own key each time. I am not sure if set() works.
My problem is push({originalKey:original}) doesn't work as expected. It writes:
originalKey: goodboy
Where originalKey is just key not the parameter from the URL. Is this possible or any other solutions?
The code is like below:
exports.addMessageSet = functions.https.onRequest((req, res) => {
// Grab the text parameter.
const original = req.query.text;
const originalKey = req.query.key;
admin.database().ref('/messages/').push({originalKey:original}).then(snapshot => {
console.log('goodboy', original, originalKey);
res.redirect(303, snapshot.ref);
});
});
If you want to use a key you're generating without firebase generating another you need to use set with your key in the path
admin.database().ref('/messages/' + originalKey).set(original).then(snapshot => { });
// if originalKey is not a string use String(originalKey)
You said about originalKey not beeing a url, but everything in firebase if url based, like this you're doing
myDB
|_ messages
|_ originalKey: original
and not
myDB > messages > originalKey > original
If you need another key after the messages node i recomend using a date UNIX number, momentJS is good to handle this.
Hope it helps
Using push() will indeed generate a unique key. You will need to use either set() or update().
Note that using set() will overwrite the data at the specified location including any child nodes.

Firebase database on push get id

I am trying to imitate an insertion trigger on Firebase using the onWrite method. The insertion is done via POST requests since I am testing it (easiest way I found to check database triggers). The trigger includes writing the Firebase generated ID inside the inserted data as a new property.
My cloud function is this:
exports.onNewSeries = functions.database.ref('/series').onWrite(event => {
"use strict";
console.log(event.data.key);
console.log(event.data.current.key);
console.log(event.data.current);
});
Both first logs contain the same key (series), which actually is the key of the parent node where the new data is appended, instead of the new data key (in the quirky form of -adfaa123sdfasdf). The last log prints a Firebase structure containing the new data as well as the generated key in a _data property, however it is not accessible.
While this can be done manually after a request, I have not seen it automated in a database trigger way.
To get the generated key, make the function trigger on a specific child:
exports.onNewSeries = functions.database.ref('/series/{id}').onWrite(event => {
console.log(event.params.id);
});
Also see the Firebase documentation on handling database events.

Categories