使用查询的 Cloud Firestore 不区分大小写的排序

IT技术 javascript firebase google-cloud-firestore
2021-01-15 17:50:46

我尝试使用OrderBy从 Cloud Firestore 读取排序数据Firestore 按以下顺序返回数据:

AAA
BBB
aaa
bbb

现在,我想要的是以下内容:

AAA
aaa
BBB
bbb

我希望这个结果只使用OrderBy而不是手动排序。
有没有办法在 Firestore 中进行这样的排序?


请为我提供解决方案。

提前致谢。

2个回答

Cloud Firestore 中的排序区分大小写。没有使排序忽略大小写的标志。

实现您的用例的唯一方法是将该字段存储两次。

假设您存储“AAA”和“aaa”的字段称为myData在您的客户端代码中,您需要存储第二个字段,称为myData_insensitive存储数据的不区分大小写副本的位置。

DocA:
-> myData = 'AAA'
-> myData_insensitive = 'AAA'

DocB:
-> myData = 'aaa'
-> myData_insensitive = 'AAA'

DocC:
-> myData = 'BBB'
-> myData_insensitive = 'BBB'

DocD:
-> myData = 'bbb'
-> myData_insensitive = 'BBB'

现在您可以通过 查询和/或订购myData_insensitive,但显示myData.

关于这个领域的两个有趣的事情是:

  1. 使用 Unicode,删除大小写比“toLowerCase”更复杂
  2. 不同的人类语言会对相同的字符进行不同的排序

无需为每个排序规则创建单独的索引来解决 (2),处理 (1) 的一种实现方法是通过案例折叠。如果您只想支持现代浏览器版本,那么下面为您提供了一个 JavaScript 示例:

caseFoldNormalize = function (s){
  return s.normalize('NFKC').toLowerCase().toUpperCase().toLowerCase()
};
caseFoldDoc = function(doc, field_options) {
  // Case fold desired document fields
  if (field_options != null) {
    for (var field in field_options) {
      if (field_options.hasOwnProperty(field)) {
        switch(field_options[field]) {
          case 'case_fold':
            if (doc.hasOwnProperty(field) && Object.prototype.toString.call(doc[field]) === "[object String]") {
              doc[field.concat("_insensitive")] = caseFoldNormalize(doc[field])
            }
            break;
        }
      }
    }
  }
  return doc;
}

var raw_document = {
  name: "Los Angeles",
  state: "CA",
  country: "USA",
  structure: 'Waſſerſchloß',
  message: 'quıt quit' // Notice the different i's
};

var field_options = {
  name: 'case_fold',
  country: 'case_fold',
  structure: 'case_fold',
  message: 'case_fold'
}

var firestore_document = caseFoldDoc(raw_document, field_options);

db.collection("cities").doc("LA").set(firestore_document).then(function() {
  console.log("Document successfully written!");
}).catch(function(error) {
  console.error("Error writing document: ", error);
});

这将在 Cloud Firestore 中为您提供一个包含以下字段的文档:

{ 
 "name": "Los Angeles", 
 "state": "CA", 
 "country": "USA", 
 "structure": "Waſſerſchloß", 
 "message": "quıt quit", 
 "name_casefold": "los angeles", 
 "country_casefold": "usa", 
 "structure_casefold": "wasserschloss", 
 "message_casefold": "quit quit"
}

要处理较旧的浏览器,您可以在如何使 toLowerCase() 和 toUpperCase() 跨浏览器保持一致中看到一种解决方案

我使用 firebase 的次数越多,我就越不想使用它,这么简单的事情怎么会再次变得如此不必要的复杂
2021-03-23 17:50:46
简直难以置信!
2021-03-28 17:50:46
如果我们想从具有大量文档的现有集合中添加对字段的查询或排序支持怎么样????所以我们需要扫描所有文档并为每个文档添加小写或大写的额外字段?
2021-03-31 17:50:46

您也可以在获得结果后手动执行此操作:

docArray.sort((a, b) => {
  if (a.myData.toLowerCase() < b.myData.toLowerCase()) {
    return -1;
  }
  if (a.myData.toLowerCase() > b.myData.toLowerCase()) {
    return 1;
  }
  return 0;
});
或者更短: docArray.sort((a, b) => { return a.myData.localeCompare(b.myData) })
2021-03-28 17:50:46
这适用于小型集合,但如果您有很多集合并且在查询中使用分页,则应在将结果返回给客户端之前对其进行排序。
2021-04-07 17:50:46