如何在不修改限制的情况下进行分页?

How can i do the pagination without modifying the limit?

如何获得用户要求的相同元素?

例如,如果我这样做,用户要求 30

query = query.limit(30)
const qSnap = await query.get(); // 30 objects

qSnap.docs.forEach((doc) => { // i will get fewer than 30
  const item = doc.data().data.tools.find(t => t.trait === 'color1' && t.value == 'red');
  console.log(item)
})

我需要过滤,因为我有这个结构:

{
    name:carla
    data: "{
       sign: "carly",
       tools: [{trait:color1, value:red}, {trait:color2, value:white}] }"
    },{
    name:dany
    data: "{
       sign: "dan",
       tools: "[{trait:color1, value:blue}, {trait:color2, value:black}] 
    }"
}

或者我怎样才能增强我的结构来避免这个问题?

你需要先过滤数据,他们限制了。使用这个语法。

 const toolsFilter = {
    trait: 'color1',
    value:'red'
  }
 
 const qSnap = await query.where('tools','array-contains',toolsFilter)
                          .limit(30)
                          .get();
    
    qSnap.docs.forEach((doc) => { 
      const item = doc.data().data;
      console.log(item)
    }))

有关查询语法等的更多信息,请参阅 Firebase 在线文档。https://firebase.google.com/docs/firestore/query-data/queries

这也解释了使用查询游标进行分页https://firebase.google.com/docs/firestore/query-data/query-cursors

采用斯图尔特的回答并稍作修改(抱歉,我无法在评论中这样做)

const toolsFilter = {
    trait: 'color1',
    value:'red'
  }
 
 const qSnap = await query.where('tools','array-contains-any', toolsFilter)
                          .limit(30)
                          .get();
    
    qSnap.docs.forEach((doc) => { 
      const item = doc.data().data;
      console.log(item)
    }))

array-contains 操作检查数组是否包含特定(完整)值。它无法检查对象数组是否包含具有 属性 特定值的项目。唯一的办法就是查询数组里面的整个对象。

在此示例结构中:

data: {
   sign: "carly",
   tools: [{trait:color1, value:red}, {trait:color2, value:white}] }
}

您想查询数组映射内的对象。请参阅下面的 Firestore 屏幕截图以获得更好的可视化效果:

为了能够查询数组映射内的对象,您必须查询其中的整个对象。请参阅下面的示例查询:

// As you can see here, you need to be able to jump inside the `data.tools`
// Then query the `tools` array by using objects.
const toolsRef = db.collection("someCollection").where("data.tools", "array-contains",  {trait: "color1", value: "red"})

完整代码供参考:

const toolsRef = db.collection("someCollection").where("data.tools", "array-contains",  {trait: "color1", value: "red"})
query = toolsRef.limit(30)

query.get()
.then((querySnapshot) => {
    querySnapshot.forEach((doc) => {
        // Do anything with the result.
        console.log(doc.id, " => ", doc.data());
    });
})
.catch((error) => {
    console.log("Error getting documents: ", error);
});

结果应该是这样的:

5nwzwpxr7BmctvznEypl  =>  {
  name: 'carla',
  data: { tools: [ [Object], [Object] ], sign: 'carly' }
}

有关详细信息,请参阅 Array Memberships


更新:

Firestore 无法从文档字段中搜索其中编码了 JSON 对象的方法。您应该首先解析 JSON 对象以 get/filter 必要的数据。例如:

query = query.limit(30);
const qSnap = await query.get();

qSnap.docs.forEach((doc) => {
  const data = JSON.parse(doc.data().data);
  const items = data.tools.filter(t => t.trait === "color1" && t.value === "red");
  console.log(items);
})

但是,上面与您的类似的代码段可能会导致问题,该问题与您在查询中设置的 limit() 不同。为了增强您的结构,我建议将其放在文档字段中,就像我在上面的原始答案中给出的那样。

document
    (fields)
    |- name(string): "carla"
    |- data(map)
            |- sign(string): "carly"
            |- tools(array)
                    |- (map)
                    |   - trait(string): "color1"
                    |   - value(string): "red"
                    |-  (map)
                        - trait(string): "color2"
                        - value(string): "white"

此结构与 data 字段中编码的 JSON 对象相同。使用此结构的优点是您现在可以使用我在原始 post 上向您展示的 Firestore 进行查询。如果不使用客户端过滤,这将导致 30 个文档。如果查询找不到匹配的文档,它只会少于 30。

为此,您只需构建 JSON 对象并将数据设置到文档中。参见例如下面:

db.collection("someCollection").add({
    data: {
        sign: "carly",
        tools: [{trait: "color1", value:"red"}, {trait:"color2", value:"white"}] 
    },
    name: "carla"
 })
 .then((docRef) => {
     console.log("Document written with ID: ", docRef.id);
 })
 .catch((error) => {
     console.error("Error adding document: ", error);
 });