Firebase Firestore - OR查询替代方案

4

在这个问题Firebase Firestore - OR query中,他们说没有OR查询。这意味着我不能轻松地查询具有我之前获取到的ID数组的项。


// What I want
documentRef
    .whereField("itemId", isEqualTo: "id1")
    .orWhereField("itemId", isEqualTo: "id3")

// or
documentRef
    .whereField("itemId", in: idArray)

由于这种方式不起作用,查询数据有哪些更好的选项呢?


  1. 获取所有数据并在本地检查

我可以获取所有记录并在设备上检查ID,但问题在于它可能多达1000条记录,而用户可能只需要其中的三条。


  1. 对所有项目进行单独的查询

我可以为用户需要的每个项目执行查询whereField("itemId", isEqualTo: "id")。如果用户只需要几个项目,那么这将是一个很好的选择,但是如果用户需要所有项目,这个解决方案将比第一个解决方案慢得多。(除非您可以批量读取)


  1. 移动数据

我认为我可以将已购买的数据移动到Item集合中:Items/itemid/PurchasedBy/uid,但我想检索用户购买的Item,并且我不知道如何查询嵌套集合内的字段。我也不知道这是否是数据的正确位置。


我的数据:

Users/uid/PurchasedItems/itemid

    payedInMoney: "$0.00"
    payedInCoins: "100"
    itemId: "itemid"
    timeStamp: timestamp

Items/itemid

    itemId: "itemid"
    // Other item info

编辑:

我选择了第一种方法,因为这是我在RTDB上的做法,但即使启用持久性并使用addSnapshotListener,Firestore的速度也远远不及RTDB的实现。我测量了时间,看起来Firestore至少比RTDB慢4倍(两者都启用了持久性)。

// iPad 5 (2017) - iOS 11
RTDB:  50-100ms
FST:  350-450ms

// iPad Air (2014) - iOS 10
RTDB: 100-150ms
FST:  700-850ms

// iPad Mini (2012) - iOS 9
RTDB: 150-200ms
FST:  2900-3200ms

编辑2:

决定继续使用RTDB,直到Firestore上的持久性真正起作用。

编辑3:

被接受的答案解决了这个问题,尽管它没有解决我的所有问题,但可能会帮助其他人。

在使用Firestore进行仅一个查询的测试后,结果仍然需要比在RTDB中进行嵌套查询更长时间才能得出,因此我将暂时坚持我的决定。


你想要展示的数据是什么?是某个用户购买的所有商品吗?在这个查询中,你需要从/items/itemid获取哪些数据? - Sam Stern
@hatboysam 确实,当我尝试展示用户购买的商品时,我会一次性获取该商品的所有数据,因此当用户点击该商品时,我不需要再进行另一个调用。 - Casper Zandbergen
2个回答

1
你可以使用rxjs组合Observables;
orQuery(){

    const $one = this.afs.collection("items", ref => ref.where("itemId","==","1")).valueChanges();
    const $two = this.afs.collection("items", ref => ref.where("itemId","==","3")).valueChanges();

    return combineLatest($one,$two).pipe(
        map(([one, two]) => [...one, ...two])
    )
}

getOr(){
    this.orQuery().subscribe(data => console.log(data))
}

1
这似乎是复制一些物品数据的好例子。我假设一些物品属性,比如“名称”,是不可变的,因此可以将其存储在PurchasedItems子集合中,而不必担心未来的更新。
因此,如果将一些数据添加到PurchasedItems中:
Users/uid/PurchasedItems/itemid

    // Existing 
    payedInMoney: "$0.00"
    payedInCoins: "100"
    itemId: "itemid"
    timeStamp: timestamp

    // Add these
    name: "Item Name"
    url: "http://foo.bar/123"

然后,您将拥有足够的信息来在单个查询中显示用户已购买物品的列表,而无需通过ID查找每个物品。

这个回答适用于我的问题,所以我会接受它作为答案,但在我的情况下,我有三种购买商品的方式:通过应用程序(payedInCoins),通过网站(payedInMoney)和通过苹果应用内购买。这些IAP不会保存在我的端上,因此我不能只添加一个名称字段,我仍然需要循环遍历所有我的项目,找到与苹果匹配的iapid的项目。 - Casper Zandbergen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接