Pour ce tutoriel, nous utiliserons le official dummy dataset
, qui contient de nombreux documents sur les restaurants de la région de New York.
Voici un exemple de la structure de base du document dans cette collection, en utilisant le .findOne()
méthode :
> db.restaurants.findOne()
{
"_id" : ObjectId("56c651e7d84ccfde319961af"),
"address" : {
"building" : "469",
"coord" : [
-73.961704,
40.662942
],
"street" : "Flatbush Avenue",
"zipcode" : "11225"
},
"borough" : "Brooklyn",
"cuisine" : "Hamburgers",
"grades" : [
{
"date" : ISODate("2014-12-30T00:00:00Z"),
"grade" : "A",
"score" : 8
},
{
"date" : ISODate("2014-07-01T00:00:00Z"),
"grade" : "B",
"score" : 23
},
{
"date" : ISODate("2013-04-30T00:00:00Z"),
"grade" : "A",
"score" : 12
},
{
"date" : ISODate("2012-05-08T00:00:00Z"),
"grade" : "A",
"score" : 12
}
],
"name" : "Wendy'S",
"restaurant_id" : "30112340"
}
Le pouvoir de trouver
La pièce la plus importante du puzzle lors de la recherche dans une collection MongoDB est le simple mais flexible db.collection.find()
méthode.
Avec .find()
, vous pouvez facilement interroger une collection de documents, en passant quelques paramètres simples, et renvoyer un cursor
. Un cursor
est simplement un ensemble de résultats et peut être itéré pour manipuler ou autrement utiliser les documents pointés par le cursor
.
Comme exemple simple du .find()
méthode en action, nous essaierons de trouver tous les restaurants de notre collection qui servent Hamburgers
comme leur cuisine
:
>db.restaurants.find( { cuisine: "Hamburgers" } )
{ "_id" : ObjectId("56c651e7d84ccfde319961af"), "address" : { "building" : "469", "coord" : [ -73.961704, 40.662942 ], "street" : "Flatbush Avenue", "zipcode" : "11225" }, "borough" : "Brooklyn", "cuisine" : "Hamburgers", "grades" : [ { "date" : ISODate("2014-12-30T00:00:00Z"), "grade" : "A", "score" : 8 }, { "date" : ISODate("2014-07-01T00:00:00Z"), "grade" : "B", "score" : 23 }, { "date" : ISODate("2013-04-30T00:00:00Z"), "grade" : "A", "score" : 12 }, { "date" : ISODate("2012-05-08T00:00:00Z"), "grade" : "A", "score" : 12 } ], "name" : "Wendy'S", "restaurant_id" : "30112340" }
...
L'ensemble de résultats est assez volumineux, donc une meilleure mesure pour nos exemples de test serait de chaîner le .count()
méthode sur .find()
pour voir simplement combien de documents correspondent à notre requête :
> db.restaurants.find( { cuisine: "Hamburgers" } ).count()
433
Ça fait beaucoup de burgers !
Recherche de similarités de mots à l'aide de Regex
Maintenant que nous utilisons .find()
pour interroger notre collection, nous pouvons en fait modifier légèrement notre syntaxe et commencer à rechercher des correspondances basées sur un mot ou une phrase qui peut être partielle correspondance dans un champ donné, similaire à LIKE
opérateur pour les moteurs SQL.
L'astuce consiste à utiliser des regular expressions
(ou regex
pour faire court), qui est essentiellement une chaîne de texte qui définit un modèle de recherche. Il existe un certain nombre de regex
moteurs qui sont écrits dans une syntaxe légèrement différente, mais les fondamentaux sont tous fondamentalement les mêmes, et dans ce cas, MongoDB utilise le Perl Regex (PCRE)
moteur.
Au niveau le plus basique, une regex
expression est une chaîne (série de caractères) délimitée des deux côtés par une seule barre oblique (/
).
Par exemple, si nous voulons utiliser regex
pour effectuer la même requête que ci-dessus et savoir combien de restaurants servent des Hamburgers
, nous pouvons remplacer notre chaîne "Hamburgers"
avec /Hamburgers/
à la place :
> db.restaurants.find( { cuisine: /Hamburgers/ } ).count()
433
Les observateurs attentifs peuvent reconnaître que nous n'avons effectivement rien changé à la requête réelle que nous effectuons - nous recherchons toujours simplement tous les documents où la cuisine
le champ est égal à la chaîne "Hamburgers"
.
Cela dit, en utilisant simplement regex
au lieu d'une "chaîne entre guillemets" normale, nous pouvons commencer à rechercher des correspondances partielles de mot/phrase à la place.
Par exemple, regardons le borough
domaine pour avoir une meilleure idée de la façon dont cela fonctionne. Remarquons tout d'abord qu'il y a six arrondissements au total dans notre collection :
> db.restaurants.distinct('borough')
[
"Brooklyn",
"Bronx",
"Manhattan",
"Queens",
"Staten Island",
"Missing"
]
Utilisons maintenant regex
pour savoir combien de restaurants il y a dans le Bronx
arrondissement :
> db.restaurants.find( { borough: /Bronx/ } ).count()
2338
Mais imaginons que nous voulions trouver le nombre de restaurants où borough
commence par les trois premiers caractères "Bro"
. Nous modifierions notre regex
très légèrement, comme ceci :
> db.restaurants.find( { borough: /^Bro/ } ).count()
8424
Nous voyons plus de 6000 documents supplémentaires dans cet ensemble de résultats, ce qui est logique car non seulement nous obtenons des résultats où le borough
est "Bronx"
, mais aussi tout pour "Brooklyn"
aussi.
Le caractère caret (^
) spécifie l'emplacement dans notre chaîne qui devrait être le début , donc si nous avions un document où ces trois lettres étaient au milieu du champ, nous n'aurions pas de correspondance.
Comme autre exemple rapide, recherchons n'importe où dans le champ pour les caractères "at"
, ce qui devrait nous donner des résultats pour "Manhattan"
et "Staten Island"
:
> db.restaurants.find( { borough: /Manhattan/ } ).count()
10259
> db.restaurants.find( { borough: /Staten Island/ } ).count()
969
> db.restaurants.find( { borough: /AT/i } ).count()
11228
Effectivement, notre requête finale a combiné les deux ensembles de résultats en un seul.
Vous remarquerez peut-être que même si nos caractères "AT"
sont en majuscules dans notre regex
chaîne, mais ils sont en minuscules dans les enregistrements de documents réels, nous avons toujours renvoyé des résultats. C'est parce que nous avons également ajouté le spécial i
drapeau suivant notre barre oblique fermante regex (/
). Ceci informe la regex
moteur que nous voulons que la recherche soit case insensitive
, correspondant indépendamment des majuscules ou des minuscules.