在Firestore查询中使用Where和Order by不同字段

dwi*_*wix 8 javascript firebase reactjs google-cloud-firestore

我有一个名为 的 Firestore 集合channels,我想根据 ID 数组获取通道列表并按字段排序createdAt,这是我的函数:

  const getChannels = () => {
    const q = query(
      collection(db, "channels"),
      where(documentId(), "in", [
        "F0mnR5rNdhwSLPZ57pTP",
        "G8p6TWSopLN4dNHJLH8d",
        "wMWMlJwa3m3lYINNjCLT",
      ]),
      orderBy("createdAt")
    );
    const unsubscribe = onSnapshot(q, (snapshot) => {
      snapshot.docs.map((doc) => {
        console.log(doc.data());
      });
    });
    return unsubscribe;
  };
Run Code Online (Sandbox Code Playgroud)

但我收到这个错误

FirebaseError: inequality filter property and first sort order must be the same: __name__ and createdAt

仅当我 orderBy 时它才有效documentId()

我知道文档对此有限制,但我想知道是否有针对这种情况的解决方法。

我想这个问题的答案也不再有效了。

小智 12

您的问题的标题表明您正在尝试将where和用于orderBy不同的领域。但请注意,您使用的documentId()是 where 条件进行过滤,这不是 Firestore 文档中的字段。

\n

因此,如果您的过滤器基于documentId(),则只能使用documentId()inorderBy()子句,并且也按升序排列,因为目前 Firestore 不支持按本答案documentId()中提到的降序排序。

\n

让\xe2\x80\x99s 看看下面的例子 -

\n
const data=await db.collection("users").where(admin.firestore.FieldPath.documentId(),"in",["104","102","101"]).orderBy(admin.firestore.FieldPath.documentId()).get();\n
Run Code Online (Sandbox Code Playgroud)\n

上面的代码将在基于documentId()进行过滤后根据进行排序。\n但是应用基于 的子句documentId()并不相关,因为不应用该子句也会产生与默认情况下 Firestore 查询按升序给出文档相同的结果的顺序。这意味着以下也会产生相同的结果 -orderBy()documentId()orderBy()documentId()

\n
const data=await db.collection("users").where(admin.firestore.FieldPath.documentId(),"in",["104","102","101"]).get();\n
Run Code Online (Sandbox Code Playgroud)\n

现在 Firestore 不\xe2\x80\x99t 支持按降序排序,这documentId()意味着以下内容将不起作用 -

\n
const data=await db.collection("users").where(admin.firestore.FieldPath.documentId(),"in",["104","102","101"]).orderBy(admin.firestore.FieldPath.documentId(),"desc").get();\n
Run Code Online (Sandbox Code Playgroud)\n

这将要求创建一个索引 -

\n
The query requires an index. You can create it here:\n
Run Code Online (Sandbox Code Playgroud)\n

但如果你去那里创建一个索引,它会说 -

\n
__name__ only indexes are not supported.\n
Run Code Online (Sandbox Code Playgroud)\n

现在让我们来回答您的问题。您想要做的是基于documentId()然后orderBy()基于createdAt不可能的字段进行过滤,并且会给出以下错误 -

\n
inequality filter property and first sort order must be the same.\n
Run Code Online (Sandbox Code Playgroud)\n

您可能会考虑使用两个orderBy()子句,如下所示 -

\n
const data=await db.collection("users").where(admin.firestore.FieldPath.documentId(),"in",["104","102","101"]).orderBy(admin.firestore.FieldPath.documentId()).orderBy(\xe2\x80\x9ccreatedAt\xe2\x80\x9d\n).get();\n
Run Code Online (Sandbox Code Playgroud)\n

这将不起作用并给出以下错误

\n
order by clause cannot contain more fields after the key\n
Run Code Online (Sandbox Code Playgroud)\n

我不确定您的用例,但基于 .xe2x80x99 进行过滤并不是一个好主意documentId()。如果需要基于 进行过滤documentId(),我建议在 Firestore 文档中创建一个字段,其中将包含 documentIds 并基于该字段进行过滤。

\n

现在考虑问题的标题,是的,可以对 Firestore 中的不同字段使用 where() 和 orderBy() 子句。有一些限制,您需要遵守 -

\n
\n

如果您包含具有范围比较(<、<=、>、>=)的过滤器,则您的第一个排序必须位于同一字段。

\n
\n
const data=await db.collection("users").where(\xe2\x80\x9cnumber\xe2\x80\x9d,">=", \xe2\x80\x9c101\xe2\x80\x9d).orderBy(\xe2\x80\x9ccreatedAt\xe2\x80\x9d).get(); \n
Run Code Online (Sandbox Code Playgroud)\n

上面的查询不起作用。

\n
const data=await db.collection("users").where(\xe2\x80\x9cnumber\xe2\x80\x9d,">=", \xe2\x80\x9c101\xe2\x80\x9d).orderBy(\xe2\x80\x9cnumber\xe2\x80\x9d).get(); \n
Run Code Online (Sandbox Code Playgroud)\n

上面的查询有效,您仍然可以orderBy()在不同的字段上进一步使用,如下所示 -

\n
const data=await db.collection("users").where(\xe2\x80\x9cnumber\xe2\x80\x9d,">=", \xe2\x80\x9c101\xe2\x80\x9d).orderBy(\xe2\x80\x9cnumber\xe2\x80\x9d).orderBy(\xe2\x80\x9ccreatedAt\xe2\x80\x9d).get(); \n
Run Code Online (Sandbox Code Playgroud)\n
\n

您不能按等式 (=) 或 in 子句中包含的任何字段对查询进行排序。

\n
\n
const data=await db.collection("users").where(\xe2\x80\x9cnumber\xe2\x80\x9d,"in",["104","102","101"]).orderBy(\xe2\x80\x9cnumber\xe2\x80\x9d).get();\nconst data=await db.collection("users").where(\xe2\x80\x9cnumber\xe2\x80\x9d,"==", \xe2\x80\x9c101\xe2\x80\x9d).orderBy(\xe2\x80\x9cnumber\xe2\x80\x9d).get(); \n
Run Code Online (Sandbox Code Playgroud)\n

上面两个不起作用。

\n