使用 Javascript 从 Firestore 获取随机文档

时间:2021-07-21 03:55:45

标签: javascript firebase google-cloud-firestore

我已经阅读了关于随机 java、swift 但 JS 随机文档 firestore 的文档,我找不到,我发现这个问题还没有出现在 JS 上?

迅速

postsRef.whereField("random", isGreaterThanOrEqualTo: random)
                   .order(by: "random")
                   .limit(to: 1)

JS

postsRef.where("random", ">=", random)
                   .order("random")
                   .limit(1)

这是正确的吗?

1 个答案:

答案 0 :(得分:2)

Typescript(如果使用 Javascript,请删除类型)版本,用于使用随机整数(和环绕)获取随机文档。此答案使用 Cloud 函数进行测试,但本质上您只需要复制 getDocuments 函数。

export const getRandomDoc = functions.https.onRequest(async (req, res): Promise<any> => {
  try {
    const randomDocs = await getDocuments(2)
    return res.send(randomDocs)
  } catch (err) {
    return res.send(err)
  }
});

const getDocuments = async (count: number): Promise<Array<FirebaseFirestore.DocumentData>> => {
  const randomNum = Math.floor(Math.random() * 10000)
  const snapshot = await admin.firestore().collection("col").where("rInt", ">=", randomNum).limit(count).get()
  if (snapshot.empty) {
    return getDocuments(count)
  }
  return snapshot.docs.map(d => d.data())
}

每当您向该集合添加新文档时,请同时添加 rInt 字段,该字段是 0 到 10000(包括两者)之间的整数。您在 getDoucments 函数中传递所需的文档数量。它将获取 N 个连续匹配的文档,因为它使用 limit() 方法。

在查询中,我们查找 rInt 大于或等于使用 Math.random() 生成的随机数的文档,并将结果限制为函数中传递的 count 参数。如果快照为空,我们重试该函数。 (值得添加一个逻辑,使此函数仅重复 N 次,否则递归将花费时间)。


在上面的函数中使用 .limit() 将最终连续返回 N 个文档。默认情况下,文档将按文档 ID 排序,除非您使用 orderBy 方法指定任何特定字段。相反,为每个文档单独提出请求会增加随机性。

/**
 * @param {number} count - number of documents to retrieve
 * @param {number} loopNum - number of times the loop is being repeated. Defaults to 0 
 * @param {Array<any>} curDocs - array of documents matched so far. Defaults to an empty array
 * @returns 
 */ 
const getDocuments = async (count: number, loopNum: number, curDocs: Array<any>): Promise<Array<FirebaseFirestore.DocumentData>> => {
  // Creating an array of requests to get documents
  const requests = []
  for (let i = 0; i < count; i++) {
    // New random number for each request
    const randomNum = Math.floor(Math.random() * 10000)
    console.log(`Random Num: ${randomNum}`);
    requests.push(admin.firestore().collection("col").where("rInt", ">=", randomNum).limit(1).get())
    // limit is set to 1 so each request will return 1 document only
  }
  
  // Using Promise.all() to run all the promises
  const snapshots = await Promise.all(requests)
  
  // Removing empty snapshots
  const filteredSnapshots = snapshots.filter(d => !d.empty)

  // Creating an array of doc data
  const matchedDocs = filteredSnapshots.map(doc => doc.docs[0].data())
  
  // If documents received are less than requested,
  // repeat the function
  if (matchedDocs.length !== count) {
    // If the function is repeated 5 times,
    // return with whatever has matched so far
    if (loopNum + 1 === 5) {
      console.log("Returning CurDocs")
      return curDocs
    }
    return getDocuments(count, loopNum + 1, [...curDocs, ...matchedDocs])
  }
  
  // Return if you get requested num of docs in first go
  return snapshots.map(d => d.docs[0].data())
}

// Calling the function
getDocuments(5, 0, [])

请注意,如果您请求的文档少于或等于 10 个,则可以使用 in 运算符。 in 运算符将同一字段上的最多 10 个等式 (==) 子句与逻辑 OR 组合在一起。


对于 @Dan McGrath, check this answer 的原始版本 (swift)。

相关问题