Basically, I'm trying to replicate my data that's already in firebase into algolia through firebase cloud functions. The code doesn't compile and I can't seem to figure out why.
I'm using typescript, not javascript and am following this article right here.
https://medium.com/#soares.rfarias/how-to-set-up-firestore-and-algolia-319fcf2c0d37
I'm also working in VScode
// This is at the top of my file
const algoliasearch = require('algoliasearch')
const algoliaClient =
algoliasearch(functions.config().algolia.appid,
functions.config().algolia.apikey)
export const sendCollectionToAlgolia =
functions.https.onRequest(async (req, res) =>
{
const collectionIndex = algoliaClient.initIndex('Organizations')
const db = admin.firestore()
const algoliaRecords = []
const querySnapshot = await db.collection("Organizations").get()
querySnapshot.docs.forEach(doc => {
const document = doc.data()
const record = {
objectID: doc.id,
"orgUsername": document.orgUsername,
"orgName": document.orgName,
"school": document.school
}
algoliaRecords.push(record)
})
collectionIndex.saveObjects(algoliaRecords, (_error: any, content:
any) => {
res.status(200).send("COLLECTION was indexed to Algolia
successfully.");
})
})
I keep getting the compile error that says "Variable 'algoliaRecords' implicitly has type 'any[]' in some locations where its type cannot be determined" and I do not know how to fix it. I'm relatively new to algolia but have been doing cloud functions for a little bit.
This happens because algoriaRecords does not have an explicit type. Typically, TypeScript will infer types based on what you end up assigning later on. However, each subsequent algoriaRecords.push() operation evolves the type of the variable in accordance with the elements added to it.
A quick fix to this is by explicitly giving a type to algoriaRecords like such:
const algoriaRecords:Object[] = []
Furthermore, you can make TypeScript tolerate params with no types declared, see here for more information by configuring your tsconfig.js file and settting the noImplicitAny to false while removing the strict rule
// "strict": true
"noImplicitAny" : false
Related
I am working on react native application I use firebase as my backend. I fetch data from firebase real time database and render it on the page. But now I want my application to be supported offline.
I used following two functions for rendering.
For listings from database
const loadListings = () => {
let data = [];
listingRef.orderByChild("created_at").on("value", (snapshot) => {
data = [];
snapshot.forEach((listing) => {
data.push(listing.val());
});
cache.store("listings", data.slice(0, 10)); // only stores latest ten listings
setListings(data);
setLoading(false);
});
};
and then use it inside useEffect like.
useEffect(() => {
loadListings();
}, []);
and for listings from cache I used this.
const loadListingsCached = async () => {
let data = await cache.get("listings");
setListings(data);
};
Now I cant put a check inside firs function as effect hook will run only one time and initialy network status is null. its not defined.
how do I achieve this?
by the way link to package I used for detecting connectivity
Edit
I used this hook as second argument to useEffect() but didn't work for me
const netInfo = useNetInfo();
I
What you want to achieve is make the code different depending on what is the network status. In the answer linked by #Rohit there is my answer about how to check the network connectivity with Net Info Package.
What you have to do is make the effect dependant on the status change. You should pass it as a argument to the effect.
const netInfo = useNetInfo();
useEffect(() => {
loadListings();
}, [netInfo]);
This way the code will always run when a network change is detected. I hope this is what you wanted to achive. Please be more specific about you goal and what is the problem. Current questions does not specify if the hook is not working, or the rendering function does not trigger etc.
I have these two nodes that I need to get on a single http call. I am trying to achieve this by using async/await to get the two nodes and then combine them using concat or forEach. But it seems that even though I am awaiting responses, inside the function they are still promises and not the data itself. This is my basic example:
exports.searchVisit = functions.https.onRequest(async (req, res) => {
const today = new Date(Date.now());
let todayVisits = await admin.database().ref('/visits/').once('value');
let frequentVisits = await admin.database().ref('/frequent_visits/').once('value');
console.log(todayVisits); // Prints an object (I guess it is a promise)
res.status(200).send(todayVisits); // Returns correctly the data on visits collection
});
How could I achieve to return todayVisits and frequentVisits combined? Thanks in advance.
In your code, todayVisits is a DataSnapshot type object. It is not a promise. Logging that DataSnapshot object is not likely to be useful. If you want to see the raw data inside that snapshot, call val() on it to get a JavaScript object with the entire set of data in that snapshot. This is also what you probably want to send to the client (not the entire contents of the DataSnapshot).
The following code, merging the two JavaScript objects obtained with val(), as explained by Doug, should do the trick:
exports.searchVisit = functions.https.onRequest(async (req, res) => {
const today = new Date(Date.now());
let todayVisits = admin.database().ref('/visits/').once('value');
let frequentVisits = admin.database().ref('/frequent_visits/').once('value');
const [todayVisitsSnap, frequentVisitsSnap] = await Promise.all([
todayVisits,
frequentVisits
]);
res.status(200).send({ ...todayVisitsSnap.val(), ...frequentVisitsSnap.val() });
});
Basically the question again:
Suppose there is a collection called 'People'.
Firestore functions can detect changes to a particular document, but is there anyway of knowing when a document(say 'Person1') is added to the collection using firebase functions?
If not, is there any alternate way to get to know when a document is added?
There is a specific function type that only triggers when a document gets created. From the documentation comes this example of how to use it:
exports.createUser = functions.firestore
.document('users/{userId}')
.onCreate((snap, context) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const newValue = snap.data();
// access a particular field as you would any JS property
const name = newValue.name;
// perform desired operations ...
});
So I am very new to Firebase and also this is the first time I use TypeScript (no JavaScript experience either), and here is what I try to do. I have a JSON structure that I want my cloud function to add to database every time some action happens. My question is the following - could you point me to the right direction, on where I can get info besides official documentation, maybe some code examples would be great. Here is the JSON format I want to push to database. I want this to appear just like Firebase structures data in the console, nested nodes etc.
{
'Player': {
'id':'name',
'visible': {
'place': 'a1',
'sign': 'rock'
}
}
}
In your cloud function, you can use code like this to update the database:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
// In your function
//##########################################
var playerRef = admin.database().ref('/Player');
// You can group multiple updates in an object
var updates = {};
updates['id'] = 'name';
updates['visible'] = {
place: 'a1',
sign: 'rock'
};
// Make sure to return the promise
return playerRef.update(updates);
//##########################################
Within my Google Firebase Firstore database I would like to gather aggregative data such as how many documents a collection has. Since Firestore does not provide aggregative queries I'm attempting to write a cloud function that will increment a field every time a document is added to the database which will contain the number of documents a collection has.
The problem I'm having is I cannot for the life of me figure out how to grab documents from Firestore within a cloud function using nodejs.
Here's what I'm doing:
At the top of my index.js file I configure the admin SDK and what have you like this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
Then for my cloud function I do this:
exports.createPost = functions.firestore
.document('posts/{post_id}')
.onCreate(event => {
// Get the post object
var post = event.data.data();
var senderID = post["sender_id"]; // This is not null
// Access to user's document and the main ledger document
const userDocRef = admin.database().ref('/users').orderByChild("user_id").equalTo(senderID).once('value')
const ledgerDocRef = admin.database().ref('/posts/ledger').once('value');
return Promise.all([userDocRef, ledgerDocRef]).then(snapshot => {
const user = snapshot[0].val();
const ledger = snapshot[1].val();
console.log("user => "+user); // Logs: user => null
console.log("ledger => "+ledger); // Logs: ledger => null
const userPostCount = user["user_name"];
const globalPostCount = ledger["global_post_count"] + 1;
const userUpdate = user.update({"post_count" : userPostCount});
const ledgerUpdate = ledger.update({"global_post_count" : globalPostCount});
return Promise.all([userUpdate, ledgerUpdate]);
});
});
I end up with the error:
TypeError: Cannot read property 'global_post_count' of null
at Promise.all.then.snapshot
Which I figure means something is wrong with my query but I don't know what. Both the users and posts are root level collections.
Im also getting a warning that says:
Billing account not configured. External network is not accessible and
quotas are severely limited.
From what I've read online, I don't think that effects it but I thought it was worth noting.
Please help.
Looks like you've written a Firestore trigger, but are then reaching into Realtime Database for queries:
const userDocRef = admin.database().ref('/users').orderByChild("user_id").equalTo(senderID).once('value')
const ledgerDocRef = admin.database().ref('/posts/ledger').once('value');
If your RTDB is empty, these queries will also end up empty.
To query Firestore, you need to be using admin.firestore() instead of admin.database(). Firestore has a mostly different API (via the Cloud SDK I just linked) than RTDB, but they are similar in some ways.