Accesssing Firebase Firestore from a script - firebase

I have a flutter Andriod app that can be used to store data in the firestore. Now I want to access that stored data from a Dart script to perform some operations on the data.
How can I access the firestore with a Dart script?
Updated the question: Looking only for dart package/library to access firebase firestore.

The Firebase docs provides good help with how to set up environment and a lot of examples.

It is possible with firedart.
import 'package:firedart/firedart.dart';
String pi = 'example-app';
void main(List<String> arguments) async {
Firestore.initialize(pi);
var map = await Firestore.instance.collection("users").get();
print(map);
}

Related

Deploy a Cloud Function to different Firebase projects

I have two firebase projects, one for development (project-dev) and one for production (project-prod).
I initialized firebase CLI for writing and deploying cloud functions linked to project-prod. Then I ran firebase use --add and added project-dev so that I can deploy the same function to both projects; I don't want to rewrite the same function twice.
At this point, I faced the problem. Into the function, I have to write something to the realtime database, but when I deploy the function to project-dev it writes to project-prod's database.
What I want to achieve is that the function has to refer to the database of the project that it is deployed to. So that I have one function and when it is deployed to project-dev it writes to project-dev's database and when it is deployed to project-prod it writes to project-prod's database.
Is it possible to achieve that? If not, what's the way to go?
EDIT
Function code:
exports.AddOrders= functions.https.onRequest(async (req, res) => {
async function addOrder(key, value) {
var ref = app.database().ref("/orders");
return ref.child(key).set(value);
}
var orders = req.body['orders'];
var promises = [];
for (var key in orders) {
promises.push(addOrder(key, orders[key]));
}
Promise.all(promises).then(
_ => {
res.sendStatus(200);
return null;
}
).catch(err => {
res.send(err);
})
});
(This function works fine, the problem is that it writes on the wrong database)
After you add a project with firebase use --add <projektName> you need to select it with firebase use <projectName>. Then you can deploy to the selected project with firebase deploy or firebase deploy --only functions.
This is the answer for anyone wondering what the problem was.
He was initialising the admin sdk with the credentials of a service account tied to the production project. The solution was to change it to admin.initializeApp() without passing any arguments. This made Firebase use the default credentials for each project.
I know its a common mistake but again, here is the link to the corresponding documentation https://firebase.google.com/docs/admin/setup

Flutter Firebase storage instance appears uninitialized

I'm writing a mobile application in Flutter and have encountered an issue relating to Firebase Storage. Part of the application needs to take an picture with the device's camera and upload it to a Firebase Storage bucket.
The upload function was working until I added some authentication functionality among other small changes.
Here is the issue:
It appears that the Firebase storage instance is uninitialized. I have seen some examples showing that Firebase may be initialized with a function that takes the api key, bucket, and such as arguments. The google documentation never refers to this function, however, and it instead recommends to copy GoogleService-Info.plist and google-services.json into the project. I've done this, and it works. The authentication api and the Firestore api, both of which I am also using in the app, both work properly. It is just Firebase storage that is problematic.
In my main function, for instance, I added the following code to show the problem.
Future<void> main() async{
// setup camera
WidgetsFlutterBinding.ensureInitialized();
final cameras = await availableCameras();
// look here!!
print('firestore: ${Firestore.instance.app}');
print('storage: ${FirebaseStorage.instance.app}');
runApp(MyApp(cameras: cameras));
}
And upon running the app (on a physical device), this is the console output:
Restarted application in 1,097ms.
flutter: firestore: FirebaseApp(__FIRAPP_DEFAULT)
flutter: storage: null
I am really stumped as to what might cause this partial failure of Firebase to initialize. I've tried changing the access rules in the Firebase console but this has no effect. Below I've pasted the section of my pubspec.yaml file having do do with Firebase includes.
# Firebase
firebase_core: ^0.4.0+9
firebase_analytics: ^5.0.2
firebase_auth: ^0.14.0+5
cloud_firestore: ^0.12.9+5
firebase_storage: ^3.0.8
Also, here is the code that makes the request to the Storage API. Again, I don't think this is the issue because the instance is null from the beginning, but here it is for the sake of completeness:
// saves a locally stored image at local_uri as name. After the storage task
// is complete, the DocumentReference ref is updated with the new url
Future<void> _save_storage(String name, String local_uri, DocumentReference ref) async {
StorageReference storage_reference;
storage_reference = FirebaseStorage.instance.ref().child('images/$name');
final StorageUploadTask upload_task = storage_reference.putFile(io.File(local_uri));
final StorageTaskSnapshot download_url = (await upload_task.onComplete);
final String url = (await download_url.ref.getDownloadURL());
// now, update the file in the database to point to the correct storage
// url
Firestore.instance.runTransaction((transaction) async {
await transaction.update(ref, {'image_url' : url});
});
}
Frustratingly, this issue throws no exceptions. Files are simply not uploaded to the bucket. I know that the instance fields are uninitialized by doing some random probing in debug mode. Also, I have found that the above StorageUploadTask instance has an error code of -13000, but I have not found any documentation on this error code anywhere.
I am very new to both Flutter and Firebase, so I think part of the issue here is that I don't understand how Firebase instances are created. I would appreciate any guidance on this issue. Thank you.
Solved! I have a cache running alongside the Firebase storage which was allowed to rename the file while the upload was occurring. Now, the renaming task is blocked until the upload is complete. I'm still not sure why the Firebase storage instance is not initialized with the data I would expect, but since it's working now I'm willing to overlook that.

Server-side geolocation distance calculation with Firebase/Firestore [duplicate]

GeoFire is tightly coupled to the Realtime Database, while geo-queries are a common functional dependency of many apps that are looking to migrate to Firestore. Is there any way to replicate the hashing/retrieval of locations in the Firestore environment?
Edit (Dec 17th, 2020): we have recently released a set of geo utility libraries and a guide to explain how to use them to implement simple geo queries on Firestore!
https://firebase.google.com/docs/firestore/solutions/geoqueries
While we still don't have native geo queries in the database, these Android, iOS, and Web libraries will help you use Geohashes to get geo querying functionality.
Edit (July 1st, 2019): When I originally wrote the answer below I was optimistic that native geo queries would come to Cloud Firestore soon, which clearly did not happen. It's still in the long-term plans, but for now the best option is to use a community-built library or make your own using either GeoHashes or the S2 Geometry library.
The GeoFire libraries for Realtime Database were built using GeoHashes and porting the logic of those libraries to Cloud Firestore should be relatively simple.
Sam from the Cloud Firestore team here. As SUPERCILEX said, Cloud Firestore has support for the GeoPoint data type already. We are working hard to bring native geo queries to the product.
Because native geo queries are coming, we will not be porting GeoFire to Cloud Firestore. Instead we will redirect that engineering effort to getting the native queries sooner.
If you need geo queries today and don't want to build your own library, stick with Realtime Database!
GREAT NEWS. There is now a library for both iOS and Android that replicates GeoFire for Firestore. The library is called GeoFirestore. It has full documentation and is well tested. I currently use it in my app and it works brilliantly. The code is very similar to that of GeoFire so it should only take a few minutes to learn.
A solution that comes to mind is to add on the Realtime Database just for geo-queries and synchronize the two databases with Cloud Functions, much like Google suggests with presence.
In my case it's not even necessary to synchronize much; I just keep a list of uids with their locations on the Realtime Database and do all geo-queries there.
A new project has been introduced since the original poster first ask this question. The project is called GEOFirestore.
With this library you can perform queries like query documents within a circle:
const geoQuery = geoFirestore.query({
center: new firebase.firestore.GeoPoint(10.38, 2.41),
radius: 10.5
});
You can install GeoFirestore via npm. You will have to install Firebase separately (because it is a peer dependency to GeoFirestore):
$ npm install geofirestore firebase --save
The Javascript solution for GeoQuery with Firestore is to use GeoFirestore as Nikhil Sridhar said. But is a quite difficult to use (or it was for me).
First of all you have to initialize a GeoFirestore reference.
var firebase = require('firebase-admin');
var GeoFirestore = require('geofirestore');
// Create a Firestore reference
const firestore = firebase.firestore();
// Create a GeoFirestore reference
const geofirestore = new GeoFirestore.GeoFirestore(firestore);
// Create a collection reference but using geofirestore collections
// this is where you save the geofirestore documents with its structure
const geocollection = geofirestore.collection('userPositions');
After you have your collection initialized, the first step is save a document with the specified structure
{
g: string;
l: GeoPoint;
d: DocumentData;
}
geofirestore.collection('userPositions').doc(id).set({ coordinates: new firebase.firestore.GeoPoint(0, 0)}).then(res => {
return res;
}).catch(err => {
console.log(err);
});
Only when you have your collection with geofirestore documents, you can query about them as the example said.
// Create a GeoQuery based on a location
const query = geocollection.near({ center: new firebase.firestore.GeoPoint(0, 0), radius: 1000 });
// Get query (as Promise)
query.get().then((value) => {
console.log(value.docs); // All docs returned by GeoQuery
});
Hope this steps help you!
Cloud Firestore natively supports geo points. See the supported data types. And you'll find the GeoPoint class which you can use to set data and also query it:
query.whereEqualTo("location", GeoPoint(lat, long))

Is there a way to use GeoFire with Firestore?

GeoFire is tightly coupled to the Realtime Database, while geo-queries are a common functional dependency of many apps that are looking to migrate to Firestore. Is there any way to replicate the hashing/retrieval of locations in the Firestore environment?
Edit (Dec 17th, 2020): we have recently released a set of geo utility libraries and a guide to explain how to use them to implement simple geo queries on Firestore!
https://firebase.google.com/docs/firestore/solutions/geoqueries
While we still don't have native geo queries in the database, these Android, iOS, and Web libraries will help you use Geohashes to get geo querying functionality.
Edit (July 1st, 2019): When I originally wrote the answer below I was optimistic that native geo queries would come to Cloud Firestore soon, which clearly did not happen. It's still in the long-term plans, but for now the best option is to use a community-built library or make your own using either GeoHashes or the S2 Geometry library.
The GeoFire libraries for Realtime Database were built using GeoHashes and porting the logic of those libraries to Cloud Firestore should be relatively simple.
Sam from the Cloud Firestore team here. As SUPERCILEX said, Cloud Firestore has support for the GeoPoint data type already. We are working hard to bring native geo queries to the product.
Because native geo queries are coming, we will not be porting GeoFire to Cloud Firestore. Instead we will redirect that engineering effort to getting the native queries sooner.
If you need geo queries today and don't want to build your own library, stick with Realtime Database!
GREAT NEWS. There is now a library for both iOS and Android that replicates GeoFire for Firestore. The library is called GeoFirestore. It has full documentation and is well tested. I currently use it in my app and it works brilliantly. The code is very similar to that of GeoFire so it should only take a few minutes to learn.
A solution that comes to mind is to add on the Realtime Database just for geo-queries and synchronize the two databases with Cloud Functions, much like Google suggests with presence.
In my case it's not even necessary to synchronize much; I just keep a list of uids with their locations on the Realtime Database and do all geo-queries there.
A new project has been introduced since the original poster first ask this question. The project is called GEOFirestore.
With this library you can perform queries like query documents within a circle:
const geoQuery = geoFirestore.query({
center: new firebase.firestore.GeoPoint(10.38, 2.41),
radius: 10.5
});
You can install GeoFirestore via npm. You will have to install Firebase separately (because it is a peer dependency to GeoFirestore):
$ npm install geofirestore firebase --save
The Javascript solution for GeoQuery with Firestore is to use GeoFirestore as Nikhil Sridhar said. But is a quite difficult to use (or it was for me).
First of all you have to initialize a GeoFirestore reference.
var firebase = require('firebase-admin');
var GeoFirestore = require('geofirestore');
// Create a Firestore reference
const firestore = firebase.firestore();
// Create a GeoFirestore reference
const geofirestore = new GeoFirestore.GeoFirestore(firestore);
// Create a collection reference but using geofirestore collections
// this is where you save the geofirestore documents with its structure
const geocollection = geofirestore.collection('userPositions');
After you have your collection initialized, the first step is save a document with the specified structure
{
g: string;
l: GeoPoint;
d: DocumentData;
}
geofirestore.collection('userPositions').doc(id).set({ coordinates: new firebase.firestore.GeoPoint(0, 0)}).then(res => {
return res;
}).catch(err => {
console.log(err);
});
Only when you have your collection with geofirestore documents, you can query about them as the example said.
// Create a GeoQuery based on a location
const query = geocollection.near({ center: new firebase.firestore.GeoPoint(0, 0), radius: 1000 });
// Get query (as Promise)
query.get().then((value) => {
console.log(value.docs); // All docs returned by GeoQuery
});
Hope this steps help you!
Cloud Firestore natively supports geo points. See the supported data types. And you'll find the GeoPoint class which you can use to set data and also query it:
query.whereEqualTo("location", GeoPoint(lat, long))

Can Firebase RemoteConfig be accessed from cloud functions

I'm using Firebase as a simple game-server and have some settings that are relevant for both client and backend and would like to keep them in RemoteConfig for consistency, but not sure if I can access it from my cloud functions in a simple way (I don't consider going through the REST interface a "simple" way)
As far as I can tell there is no mention of it in the docs, so I guess it's not possible, but does anyone know for sure?
firebaser here
There is a public REST API that allows you to read and set Firebase Remote Config conditions. This API requires that you have full administrative access to the Firebase project, so must only be used on a trusted environment (such as your development machine, a server you control or Cloud Functions).
There is no public API to get Firebase Remote Config settings from a client environment at the moment. Sorry I don't have better news.
This is probably only included in newer versions of firebase (8th or 9th and above if I'm not mistaken).
// We first need to import remoteConfig function.
import { remoteConfig } from firebase-admin
// Then in your cloud function we use it to fetch our remote config values.
const remoteConfigTemplate = await remoteConfig().getTemplate().catch(e => {
// Your error handling if fetching fails...
}
// Next it is just matter of extracting the values, which is kinda convoluted,
// let's say you want to extract `game_version` field from remote config:
const gameVersion = remoteConfigTemplate.parameters.game_version.defaultValue.value
So parameters are always followed by the name of the field that you defined in Firebase console's remote config, in this example game_version.
It's a mouthful (or typeful) but that's how you get it.
Also note that if value is stored as JSON string, you will need to parse it before usage, commonly: JSON.parse(gameVersion).
Similar process is outlined in Firebase docs.

Resources