如何在Google云功能内使用geofirex

时间:2019-04-30 19:42:30

标签: typescript google-cloud-functions geofirex

我有一个用例,需要在Google Cloud Functions中使用geofirex库。该库的init函数需要FirebaseApp实例。是否可以在云函数内部对其进行初始化,以便使用firebase-admin查询firestore数据库?

我尝试过的..

功能> src> 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)

谢谢。

3 个答案:

答案 0 :(得分:2)

-也许这是完整的解决方案-

两个步骤:-

  
      
  1. 将Geopoint和Geohashhes添加到Firestore中
  2.   
  3. 查询地理位置数据
  4.   

第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和Geohash:-

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地理位置:-

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

答案 1 :(得分:1)

在第二次检查时,似乎是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。 :)

答案 2 :(得分:0)

问题已解决,如下所示:

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返回了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();

,但是不幸的是,它不起作用。我收到以下错误:

  

错误:参数“ onNext”不是有效的函数。       在Validator处。(匿名函数)。值[as isFunction](/srv/node_modules/@google-cloud/firestore/build/src/validate.js:99:27)       在Query.onSnapshot(/srv/node_modules/@google-cloud/firestore/build/src/reference.js:1524:25)       在Observable._subscribe(/srv/node_modules/geofirex/dist/index.cjs.js:1597:33)       在Observable._trySubscribe(/srv/node_modules/rxjs/internal/Observable.js:44:25)       在Observable.subscribe(/srv/node_modules/rxjs/internal/Observable.js:30:22)       在MapOperator.call(/srv/node_modules/rxjs/internal/operators/map.js:32:23)       在Observable.subscribe(/srv/node_modules/rxjs/internal/Observable.js:25:31)       在Object.subscribeToResult(/srv/node_modules/rxjs/internal/util/subscribeToResult.js:12:23)       在CombineLatestSubscriber._complete(/srv/node_modules/rxjs/internal/observable/combineLatest.js:76:46)       在CombineLatestSubscriber.Subscriber.complete(/srv/node_modules/rxjs/internal/Subscriber.js:78:18)