web-dev-qa-db-fra.com

Longueur de la valeur du champ de chaîne dans mongoDB

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

58
SURYA GOKARAJU

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 par abc.

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.

120
chridam

Voici l'une des façons dont vous pouvez y arriver.

db.usercollection.find({ $where: 'this.name.length < 4' })
5
Rajdeep Gautam

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;

}
}})
2
Udara Gunathilake

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
0
Fumiya Karasawa