web-dev-qa-db-fra.com

Tri insensible à la casse Cloud Firestore à l'aide d'une requête

J'ai essayé de lire les données triées de Cloud Firestore en utilisant OrderBy. Et Firestore a renvoyé les données comme ordre suivant:

AAA
BBB
aaa
bbb

Maintenant, ce que je veux, c'est quelque chose comme ceci:

AAA
aaa
BBB
bbb

Je veux ce résultat uniquement en utilisant OrderBy pas par tri manuel.
Existe-t-il un moyen de trier comme ça dans Firestore?


Veuillez me fournir une solution pour cela.

Merci d'avance.

16
Mitul Gedeeya

Le tri dans Cloud Firestore est sensible à la casse. Il n'y a pas d'indicateur pour que le tri ignore le cas.

La seule façon de réaliser votre cas d'utilisation est de stocker le champ deux fois.

Disons que votre champ qui stocke 'AAA' et 'aaa' s'appelle myData. Dans votre code client, vous devrez stocker un deuxième champ appelé myData_insensitive où vous stockez une copie insensible à la casse des données.

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

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

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

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

Vous pouvez maintenant interroger et/ou commander par myData_insensitive, mais affichez myData.

Deux choses intéressantes à propos de ce domaine sont:

  1. Avec Unicode, la suppression de cas est plus complexe que simplement "toLowerCase"
  2. Différentes langues humaines trieront différemment les mêmes caractères

Sans créer d'index distincts pour chaque classement à résoudre (2), une approche d'implémentation à traiter (1) consiste à replier la casse. Si vous souhaitez uniquement prendre en charge les versions de navigateur modernes, voici ce qui vous donne un exemple 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);
});

Cela vous donnera un document dans Cloud Firestore avec les champs suivants:

{ 
 "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"
}

Pour gérer un navigateur plus ancien, vous pouvez voir une solution dans Comment puis-je rendre toLowerCase () et toUpperCase () cohérents entre les navigateurs

20
Dan McGrath

Vous pouvez également le faire manuellement après avoir obtenu vos résultats:

docArray.sort((a, b) => {
  if (a.myData.toLowerCase() < b.myData.toLowerCase()) {
    return -1;
  }
  if (a.myData.toLowerCase() > b.myData.toLowerCase()) {
    return 1;
  }
  return 0;
});
0
Jus10