Le type de données du champ est String. Je voudrais récupérer les données où la longueur de caractère du nom de champ est supérieure à 40.
J'ai essayé ces requêtes mais en renvoyant une erreur. 1.
db.usercollection.find(
{$where: "(this.name.length > 40)"}
).limit(2);
output :error: {
"$err" : "TypeError: Cannot read property 'length' of undefined near '40)' ",
"code" : 16722
}
cela fonctionne dans 2.4.9 Mais ma version est 2.6.5
Pour MongoDB 3.6 et plus récent:
Le $expr
L'opérateur permet l'utilisation d'expressions d'agrégation dans le langage de requête. Vous pouvez ainsi tirer parti de $strLenCP
opérateur pour vérifier la longueur de la chaîne comme suit:
db.usercollection.find({
"name": { "$exists": true },
"$expr": { "$gt": [ { "$strLenCP": "$name" }, 40 ] }
})
Pour MongoDB 3.4 et plus récent:
Vous pouvez également utiliser le cadre d'agrégation avec le $redact
Opérateur de pipeline vous permettant de traiter la condition logique avec le $cond
opérateur et utilise les opérations spéciales $$KEEP
pour "conserver" le document où la condition logique est vraie ou $$Prune
pour "supprimer" le document où la condition était fausse.
Cette opération est similaire à avoir un $project
pipeline qui sélectionne les champs de la collection et crée un nouveau champ contenant le résultat de la requête de condition logique, puis un suivant - $match
, sauf que $redact
utilise un seul étage de pipeline plus efficace.
En ce qui concerne la condition logique, il existe opérateurs d'agrégation de chaînes que vous pouvez utiliser $strLenCP
opérateur pour vérifier la longueur de la chaîne. Si la longueur est $gt
une valeur spécifiée, la correspondance est vraie et le document est "conservé". Sinon, il est "taillé" et jeté.
Pensez à exécuter l'opération d'agrégation suivante qui illustre le concept ci-dessus:
db.usercollection.aggregate([
{ "$match": { "name": { "$exists": true } } },
{
"$redact": {
"$cond": [
{ "$gt": [ { "$strLenCP": "$name" }, 40] },
"$$KEEP",
"$$Prune"
]
}
},
{ "$limit": 2 }
])
Si vous utilisez $where
_ , essayez votre requête sans les crochets:
db.usercollection.find({$where: "this.name.length > 40"}).limit(2);
Une meilleure requête serait de vérifier l'existence du champ, puis de vérifier la longueur:
db.usercollection.find({name: {$type: 2}, $where: "this.name.length > 40"}).limit(2);
ou:
db.usercollection.find({name: {$exists: true}, $where: "this.name.length >
40"}).limit(2);
MongoDB évalue non - $where
opérations de requête avant $where
expressions et non -$where
les instructions de requête peuvent utiliser un index. Une performance bien meilleure consiste à stocker la longueur de la chaîne dans un autre champ pour pouvoir l'indexer ou la rechercher. appliquer $where
_ sera beaucoup plus lent que cela. Il est recommandé d’utiliser des expressions JavaScript et le $where
opérateur en dernier recours lorsque vous ne pouvez pas structurer les données autrement, ou lorsque vous traitez avec un petit sous-ensemble de données.
Une approche différente et plus rapide qui évite l’utilisation de $where
opérateur est le $regex
opérateur. Considérez le modèle suivant qui recherche
db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2);
Remarque - Depuis le documents:
Si un index existe pour le champ, MongoDB met en correspondance l'expression régulière avec les valeurs de l'index, ce qui peut être plus rapide qu'une analyse de collection. Une optimisation supplémentaire peut avoir lieu si l'expression régulière est une "expression préfixe", ce qui signifie que toutes les correspondances potentielles commencent par la même chaîne. Cela permet à MongoDB de construire une "plage" à partir de ce préfixe et de ne faire correspondre que les valeurs de l'index comprises dans cette plage.
Une expression régulière est une "expression préfixe" si elle commence par un caret
(^)
ou une ancre gauche(\A)
, suivi d'une chaîne de symboles simples. Par exemple, l'expression régulière/^abc.*/
sera optimisé en comparant uniquement les valeurs de l’index commençant parabc
.De plus, alors que
/^a/, /^a.*/,
et/^a.*$/
correspondent à des chaînes équivalentes, elles ont des caractéristiques de performance différentes. Toutes ces expressions utilisent un index si un index approprié existe; toutefois,/^a.*/
, et/^a.*$/
sont plus lents./^a/
peut arrêter la numérisation après la correspondance du préfixe.
Voici l'une des façons dont vous pouvez y arriver.
db.usercollection.find({ $where: 'this.name.length < 4' })
J'ai eu un genre de scénario similaire, mais dans mon cas, la chaîne n'est pas un attribut de premier niveau. C'est à l'intérieur d'un objet. Ici, je ne trouvais pas de réponse appropriée. J'ai donc pensé partager ma solution avec vous tous (espérons que cela aidera toute personne ayant le même type de problème).
Parent Collection
{
"Child":
{
"name":"Random Name",
"Age:"09"
}
}
Ex: Si nous devons obtenir uniquement des collections dont la longueur du nom de l'enfant est supérieure à 10 caractères.
db.getCollection('Parent').find({$where: function() {
for (var field in this.Child.name) {
if (this.Child.name.length > 10)
return true;
}
}})
Requêtes avec $where
et $expr
sont lents s’il ya trop de documents.
En utilisant $regex
est beaucoup plus rapide que $where
, $expr
.
db.usercollection.find({
"name": /^[\s\S]{40,}$/, // name.length >= 40
})
or
db.usercollection.find({
"name": { "$regex": "^[\s\S]{40,}$" }, // name.length >= 40
})
Cette requête a la même signification avec
db.usercollection.find({
"$where": "this.name && this.name.length >= 40",
})
or
db.usercollection.find({
"name": { "$exists": true },
"$expr": { "$gte": [ { "$strLenCP": "$name" }, 40 ] }
})
J'ai testé chaque requête pour ma collection.
# find
$where: 10529.359ms
$expr: 5305.801ms
$regex: 2516.124ms
# count
$where: 10872.006ms
$expr: 2630.155ms
$regex: 158.066ms