如何在 google 云函数中使用 geofirex
How to use geofirex inside google cloud functions
我有一个用例,我需要在 Google Cloud Functions 中使用 geofirex 库。库的 init 函数需要 FirebaseApp 实例。是否可以在云函数中初始化它以便使用 firebase-admin 查询 firestore 数据库?
我试过的..
函数 > 源 > index.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
admin.firestore().settings({timestampsInSnapshots: true});
// Init GeoFireX
import * as firebase from 'firebase/app';
import * as geofirex from 'geofirex';
const geoFire = geofirex.init(firebase);
exports.geofenceUserNotifications = functions.https.onRequest((req, res) => {
if(!req || !req.body || !req.body.length || !req.body[0].latitude || !req.body[0].longitude || !req.body[0].uid || !req.body[0].userFcmToken){
// end function with 401 status
res.status(401).send('Authentication required.');
}
const uid = req.body[0].uid;
const userFcmToken = req.body[0].userFcmToken;
const latitude = req.body[0].latitude;
const longitude = req.body[0].longitude;
const field = 'position';
geoFire.collection('users').setPoint(uid, field, latitude, longitude).then(result => {
res.end('User geoPoint updated!');
}).catch( err => {
console.log(err);
res.end('error when update user geo point!');
});
});
函数 > package.json
{
"name": "functions",
"scripts": {
"lint": "tslint --project tsconfig.json",
"build": "tsc",
"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "~6.0.0",
"firebase-functions": "^2.1.0",
"moment": "^2.23.0",
"firebase": "^5.10.1",
"geofirex": "0.0.6",
"rxjs": "^6.3.3",
"rxjs-compat": "^6.5.1"
},
"devDependencies": {
"tslint": "~5.8.0",
"typescript": "~2.8.3"
},
"private": true
}
部署时没有错误,但调用 geofenceUserNotifications 函数时出现此错误:
TypeError: app.firestore is not a function
at new GeoFireCollectionRef (/user_code/node_modules/geofirex/dist/index.cjs.js:1465:24)
at GeoFireClient.collection (/user_code/node_modules/geofirex/dist/index.cjs.js:1639:16)
at exports.geofenceUserNotifications.functions.https.onRequest (/user_code/lib/index.js:2197:13)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /var/tmp/worker/worker.js:783:7
at /var/tmp/worker/worker.js:766:11
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
提前致谢。
第二次检查,似乎Firebase Admin SDK for Node.js does have the concept of a FirebaseApp。您可能想尝试将 admin.app()
传递给 GeofireX 以对其进行初始化。
在 Cloud Functions 中,您使用的是 Firebase Admin SDK for Node.js,它没有 FirebaseApp
.
的概念
从快速扫描来看,GeofireX 似乎只能与 Firebase 的客户端 JavaScript SDK 一起使用。您可能想要 file a feature request on its repo,甚至更好的 PR。 :)
问题解决如下:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
admin.firestore().settings({timestampsInSnapshots: true});
// Init GeoFireX
const geofirex = require('geofirex');// <-- Use require Instead of import geofirex
import { get } from 'geofirex';
const geoFire = geofirex.init(admin); // <-- admin not admin.app()
然后
exports.geofenceUserNotifications = functions.https.onRequest(async (req, res) => {
//setPoint (id, field, lat, lng)
geoFire.collection('users').setPoint(uid, field, latitude, longitude).then(result => {
res.end('User geo point is updated!');
}).catch( err => {
res.end('error when update user geo point');
return;
});
});
geoFireX 工作正常。
但现在我遇到了 geoFireX 查询的其他问题。
我尝试获取附近的项目,但 geoFireX returns Observable<object[]>
并且它在云功能中不起作用。
我尝试使用 geoFireX 的 get():
const query = geoFire.collection('places', queryRef).within(center, radius, field);
const nearbyPlaces = await get(query); // await query.pipe(operators.first()).toPromise();
但不幸的是它不起作用。我收到以下错误:
Error: Argument "onNext" is not a valid function.
at Validator.(anonymous function).values [as isFunction] (/srv/node_modules/@google-cloud/firestore/build/src/validate.js:99:27)
at Query.onSnapshot (/srv/node_modules/@google-cloud/firestore/build/src/reference.js:1524:25)
at Observable._subscribe (/srv/node_modules/geofirex/dist/index.cjs.js:1597:33)
at Observable._trySubscribe (/srv/node_modules/rxjs/internal/Observable.js:44:25)
at Observable.subscribe (/srv/node_modules/rxjs/internal/Observable.js:30:22)
at MapOperator.call (/srv/node_modules/rxjs/internal/operators/map.js:32:23)
at Observable.subscribe (/srv/node_modules/rxjs/internal/Observable.js:25:31)
at Object.subscribeToResult (/srv/node_modules/rxjs/internal/util/subscribeToResult.js:12:23)
at CombineLatestSubscriber._complete (/srv/node_modules/rxjs/internal/observable/combineLatest.js:76:46)
at CombineLatestSubscriber.Subscriber.complete (/srv/node_modules/rxjs/internal/Subscriber.js:78:18)
-- 也许这就是完整的解决方案--
两步:-
- Adding Geopoint and Geohashes into firestore
- Query with geopoint data
第 1 步解决方案:
为此,您必须添加 firebase-admin sdk 并使用 geofirex.init(admin) 配置 geofirex。
例如:
const geofirex = require('geofirex');// <-- Use require Instead of import geofirex
import { get } from 'geofirex';
const geo = geofirex.init(admin); // <-- admin not admin.app()
现在您可以像这样存储您的 Geopoint 和 Geohashes:-
const point = geo.point(40.1, -119.1);
使用 firestore 将其存储到数据库中。
第 2 步解决方案:
为此,您必须使用 firebase web sdk 来配置 geofirex。否则,您将无法从您的 firestore 数据库中查询!
例如:
import * as firebase from 'firebase';
var firebaseConfig = {
apiKey: API_KEY_HERE,
authDomain: DOMAIN_HERE,
databaseURL: FIREBASE_REALTIME_DATABASE_URL,
projectId: PROJECT_ID,
storageBucket: STORAGE_BUCKET,
messagingSenderId: MESSAGING_SENDER_ID,
appId: FIREBASE_APP_ID,
measurementId: MEASUREMENT_ID
};
firebase.initializeApp(firebaseConfig);
import geofirex = require('geofirex');// <-- Now, use import Instead of require('geofirex')
const geo = geofirex.init(firebase.app()); // <-- firebase or, firebase.app()
您可以从您的 firebase 控制台 web sdk 设置中获取 firebaseConfig。只需复制并粘贴即可! ;)
现在您可以像这样查询您的 firestore geopoint:-
router.get('/expert', (req, res, next) => {
const radius = req.query.radius
const lat = req.query.lat
const lng = req.query.lng
const field = 'position'
geo.collection('ex-pending').within(geo.point(lat, lng), radius, field).subscribe(snap => {
res.status(200).send(snap)
})
})
就是这样! :D
我有一个用例,我需要在 Google Cloud Functions 中使用 geofirex 库。库的 init 函数需要 FirebaseApp 实例。是否可以在云函数中初始化它以便使用 firebase-admin 查询 firestore 数据库?
我试过的..
函数 > 源 > index.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
admin.firestore().settings({timestampsInSnapshots: true});
// Init GeoFireX
import * as firebase from 'firebase/app';
import * as geofirex from 'geofirex';
const geoFire = geofirex.init(firebase);
exports.geofenceUserNotifications = functions.https.onRequest((req, res) => {
if(!req || !req.body || !req.body.length || !req.body[0].latitude || !req.body[0].longitude || !req.body[0].uid || !req.body[0].userFcmToken){
// end function with 401 status
res.status(401).send('Authentication required.');
}
const uid = req.body[0].uid;
const userFcmToken = req.body[0].userFcmToken;
const latitude = req.body[0].latitude;
const longitude = req.body[0].longitude;
const field = 'position';
geoFire.collection('users').setPoint(uid, field, latitude, longitude).then(result => {
res.end('User geoPoint updated!');
}).catch( err => {
console.log(err);
res.end('error when update user geo point!');
});
});
函数 > package.json
{
"name": "functions",
"scripts": {
"lint": "tslint --project tsconfig.json",
"build": "tsc",
"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "~6.0.0",
"firebase-functions": "^2.1.0",
"moment": "^2.23.0",
"firebase": "^5.10.1",
"geofirex": "0.0.6",
"rxjs": "^6.3.3",
"rxjs-compat": "^6.5.1"
},
"devDependencies": {
"tslint": "~5.8.0",
"typescript": "~2.8.3"
},
"private": true
}
部署时没有错误,但调用 geofenceUserNotifications 函数时出现此错误:
TypeError: app.firestore is not a function
at new GeoFireCollectionRef (/user_code/node_modules/geofirex/dist/index.cjs.js:1465:24)
at GeoFireClient.collection (/user_code/node_modules/geofirex/dist/index.cjs.js:1639:16)
at exports.geofenceUserNotifications.functions.https.onRequest (/user_code/lib/index.js:2197:13)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /var/tmp/worker/worker.js:783:7
at /var/tmp/worker/worker.js:766:11
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
提前致谢。
第二次检查,似乎Firebase Admin SDK for Node.js does have the concept of a FirebaseApp。您可能想尝试将 admin.app()
传递给 GeofireX 以对其进行初始化。
在 Cloud Functions 中,您使用的是 Firebase Admin SDK for Node.js,它没有 FirebaseApp
.
从快速扫描来看,GeofireX 似乎只能与 Firebase 的客户端 JavaScript SDK 一起使用。您可能想要 file a feature request on its repo,甚至更好的 PR。 :)
问题解决如下:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
admin.firestore().settings({timestampsInSnapshots: true});
// Init GeoFireX
const geofirex = require('geofirex');// <-- Use require Instead of import geofirex
import { get } from 'geofirex';
const geoFire = geofirex.init(admin); // <-- admin not admin.app()
然后
exports.geofenceUserNotifications = functions.https.onRequest(async (req, res) => {
//setPoint (id, field, lat, lng)
geoFire.collection('users').setPoint(uid, field, latitude, longitude).then(result => {
res.end('User geo point is updated!');
}).catch( err => {
res.end('error when update user geo point');
return;
});
});
geoFireX 工作正常。
但现在我遇到了 geoFireX 查询的其他问题。
我尝试获取附近的项目,但 geoFireX returns Observable<object[]>
并且它在云功能中不起作用。
我尝试使用 geoFireX 的 get():
const query = geoFire.collection('places', queryRef).within(center, radius, field);
const nearbyPlaces = await get(query); // await query.pipe(operators.first()).toPromise();
但不幸的是它不起作用。我收到以下错误:
Error: Argument "onNext" is not a valid function. at Validator.(anonymous function).values [as isFunction] (/srv/node_modules/@google-cloud/firestore/build/src/validate.js:99:27) at Query.onSnapshot (/srv/node_modules/@google-cloud/firestore/build/src/reference.js:1524:25) at Observable._subscribe (/srv/node_modules/geofirex/dist/index.cjs.js:1597:33) at Observable._trySubscribe (/srv/node_modules/rxjs/internal/Observable.js:44:25) at Observable.subscribe (/srv/node_modules/rxjs/internal/Observable.js:30:22) at MapOperator.call (/srv/node_modules/rxjs/internal/operators/map.js:32:23) at Observable.subscribe (/srv/node_modules/rxjs/internal/Observable.js:25:31) at Object.subscribeToResult (/srv/node_modules/rxjs/internal/util/subscribeToResult.js:12:23) at CombineLatestSubscriber._complete (/srv/node_modules/rxjs/internal/observable/combineLatest.js:76:46) at CombineLatestSubscriber.Subscriber.complete (/srv/node_modules/rxjs/internal/Subscriber.js:78:18)
-- 也许这就是完整的解决方案--
两步:-
- Adding Geopoint and Geohashes into firestore
- Query with geopoint data
第 1 步解决方案: 为此,您必须添加 firebase-admin sdk 并使用 geofirex.init(admin) 配置 geofirex。 例如:
const geofirex = require('geofirex');// <-- Use require Instead of import geofirex
import { get } from 'geofirex';
const geo = geofirex.init(admin); // <-- admin not admin.app()
现在您可以像这样存储您的 Geopoint 和 Geohashes:-
const point = geo.point(40.1, -119.1);
使用 firestore 将其存储到数据库中。
第 2 步解决方案: 为此,您必须使用 firebase web sdk 来配置 geofirex。否则,您将无法从您的 firestore 数据库中查询! 例如:
import * as firebase from 'firebase';
var firebaseConfig = {
apiKey: API_KEY_HERE,
authDomain: DOMAIN_HERE,
databaseURL: FIREBASE_REALTIME_DATABASE_URL,
projectId: PROJECT_ID,
storageBucket: STORAGE_BUCKET,
messagingSenderId: MESSAGING_SENDER_ID,
appId: FIREBASE_APP_ID,
measurementId: MEASUREMENT_ID
};
firebase.initializeApp(firebaseConfig);
import geofirex = require('geofirex');// <-- Now, use import Instead of require('geofirex')
const geo = geofirex.init(firebase.app()); // <-- firebase or, firebase.app()
您可以从您的 firebase 控制台 web sdk 设置中获取 firebaseConfig。只需复制并粘贴即可! ;) 现在您可以像这样查询您的 firestore geopoint:-
router.get('/expert', (req, res, next) => {
const radius = req.query.radius
const lat = req.query.lat
const lng = req.query.lng
const field = 'position'
geo.collection('ex-pending').within(geo.point(lat, lng), radius, field).subscribe(snap => {
res.status(200).send(snap)
})
})
就是这样! :D