【问题标题】:How to use geofirex inside google cloud functions如何在谷歌云功能中使用 geofirex
【发布时间】:2019-09-19 12:24:11
【问题描述】:

我有一个用例,我需要在 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)

提前致谢。

【问题讨论】:

    标签: typescript google-cloud-functions geofirex


    【解决方案1】:

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

    两步:-

    1. 将 Geopoint 和 Geohashes 添加到 Firestore 中
    2. 地理点数据查询

    第一步解决方案: 为此,您必须添加 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 地理点:-

    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

    【讨论】:

    • 还有一件事!如果您遇到 geofirex 的“订阅”方法的任何问题,那么您可以使用它进行查询:const promise = geo.collection('ex-pending').within(geo.point(lat, lng), radius, field) const snap = await get(promise) 这是异步等待方法而不是 RxJs。
    • 这显示了节点 js 后端而不是云功能的示例。它们非常相似,但就我而言,我使用的是 https.onCall 方法,这对我不起作用。
    【解决方案2】:

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

    【讨论】:

    • 感谢@Frank 的帮助。我试过const geoFire = geofirex.init(admin.app()); 不工作,但我用另一种方式做到这一点,首先const geofirex = require('geofirex'); 然后const geoFire = geofirex.init(admin.app()); 我认为这是工作但现在我在调用函数时遇到了其他问题我得到TypeError: this.app.firestore.GeoPoint is not a constructor at GeoFirePoint.get [as geoPoint] (/user_code/node_modules/geofirex/dist/index.cjs.js:1390:20) at GeoFirePoint.get [as data] (/user_code/node_modules/geofirex/dist/index.cjs.js:1411:31) at GeoFireCollectionRef.setPoint (/u....
    • 是的...虽然 GeoFireX 可能能够在您的上下文中使用,但它似乎更专注于网络。您将不得不深入研究该堆栈跟踪的 GeoFireX 源代码,以了解导致它的原因。这就是我为得到上面修改后的答案所做的,这显然解决了你的第一个问题。问题是查看堆栈跟踪指向的内容,然后从那里向后工作。
    • 我跟踪了 GeoFireX 源代码,但我无法确定问题的原因 :(node_modules/geofirex/dist/index.cjs.js:1390 处的行是:return new this.app.firestore.GeoPoint(this.latitude, this.longitude);
    • TypeError: this.app.firestore.GeoPoint is not a constructor at GeoFirePoint.get 可以通过最后调用 .data 来解决
    【解决方案3】:

    问题解决如下:

    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&lt;object[]&gt;,它在云函数中不起作用。

    我尝试使用 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.(匿名函数).values [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)

    【讨论】:

      猜你喜欢
      • 2017-11-10
      • 1970-01-01
      • 2020-10-14
      • 1970-01-01
      • 2022-12-17
      • 2017-11-14
      • 1970-01-01
      • 2019-06-07
      • 1970-01-01
      相关资源
      最近更新 更多