MichaelSolati / geofirestore-js

Location-based querying and filtering using Firebase Firestore.
https://geofirestore.com
MIT License
504 stars 58 forks source link

How to update / set geofirestore and non-geofirestore db entries in a single GeoTransaction #143

Closed dsg38 closed 4 years ago

dsg38 commented 4 years ago

Hey - great library, really useful. I have a use case with transactions which I'm not sure is supported. I am using a GeoTransaction to create a new geofirestore entry in my database. But within the same transaction, I need to update other parts of my db, which are non-geofirestore entries. Here's a minimal example:

import * as geofunctions from 'geofirestore'
import * as admin from 'firebase-admin'

export const db = admin.firestore()
export const geoDb = new geofunctions.GeoFirestore(db)

export async function geoTransactionExample() {

    const geoPoint = new admin.firestore.GeoPoint(5, 5)

    const geoDocRef = db.collection('geoDataCollection').doc()

    const geoDataEntry = {
        coordinates: geoPoint,
        extra: "extra",
        data: "data"
    }

    const normalDocRef = db.collection('normalDataCollection').doc()

    const normalEntry = {
        normal: "normal",
        data: "data"
    }

    await geoDb.runTransaction(async (t) => {

        const geotransaction = new geofunctions.GeoTransaction(t)

        // This succeeds
        geotransaction.set(geoDocRef, geoDataEntry)

        // This fails
        geotransaction.set(normalDocRef, normalEntry)

    })

}

This fails on the second non-geo set operation with Error: Invalid GeoFirestore document: could not find GeoPoint - which makes sense. But is there e.g. a flag I can pass to the set operation to allow a normal non-geo set? Or is there a different approach to achieve this within a single transaction? Or is this not currently supported?

MichaelSolati commented 4 years ago

Something not currently exposed by GeoTransactions in 3.3.1 (which you will see in the next release of GeoFirestore) is the native transaction. To access the native transaction object to run a set on you could do something like this:

    await geoDb.runTransaction(async (t) => {

        const geotransaction = new geofunctions.GeoTransaction(t)

        // This succeeds
        geotransaction.set(geoDocRef, geoDataEntry)

        // This should succeed
        geotransaction['_transaction'].set(normalDocRef, normalEntry)

    })

Note that in the next version you'll be able to access the native transaction object not like this: geotransaction['_transaction'] but like this geotransaction.native.

dsg38 commented 4 years ago

@MichaelSolati - tested, works. Fantastic, thank you.