Longueur du champ de la chaîne en mongoDB

le type de données du champ est String. J'aimerais récupérer les données lorsque la longueur des caractères du nom du champ est supérieure à 40.

j'ai essayé ces requêtes mais en retournant l'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 en 2.4.9 mais ma version est 2.6.5

41
demandé sur chridam 2015-04-11 15:10:41

3 réponses

Pour MongoDB 3.6 et versions ultérieures:

$expr l'opérateur permet l'utilisation d'expressions d'agrégation dans le langage de requête, donc vous pouvez tirer parti de l'utilisation de $strLenCP opérateur de 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 les versions plus récentes:

vous pouvez également utiliser le cadre d'agrégation $redact opérateur de pipeline qui vous permet de traiter la condition logique avec le $cond opérateur et utilise les opérations spéciales $$KEEP pour "garder" le document dans le cas où la condition logique est vraie ou $$PRUNE pour "supprimer" le document où la condition était fausse.

cette opération est similaire à avoir une $project pipeline qui sélectionne les champs de la collection et crée un nouveau champ qui contient le résultat de la requête de condition logique et ensuite un$match sauf que $redact utilise un seul étage de pipeline qui est plus efficace.

quant à la condition logique, il y a Opérateurs D'Agrégation De Chaînes De Caractères que vous pouvez utiliser $strLenCP opérateur de vérifier la longueur de la chaîne. Si la longueur est $gt à une valeur spécifiée, alors c'est un vrai match et que le document est "conservé". Sinon, il est "taillé" et s'en débarrasser.


envisagez d'exécuter l'opération d'ensemble suivante qui démontre 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 de votre requête sans l'enfermer entre parenthèses:

db.usercollection.find({$where: "this.name.length > 40"}).limit(2);

une meilleure requête serait de vérifier l'existence du champ et ensuite 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 les opérations de requête avant $where expressions et non$where les énoncés de requête peuvent utiliser un index. Une bien meilleure performance est de stocker la longueur de la chaîne un autre champ et ensuite vous pouvez indexer ou rechercher; appliquer $where sera beaucoup plus lent par rapport à cela. Il est recommandé d'utiliser les expressions JavaScript et le $where opérateur en dernier recours lorsque vous ne pouvez pas structurer les données d'une autre manière, ou lorsque vous avez affaire à un petit sous-ensemble de données.


une approche différente et plus rapide qui évite l'utilisation de $where opérateur $regex opérateur. Considérez le schéma suivant qui recherche

db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2); 

Remarque: - la docs:

si un index existe pour le champ, alors MongoDB correspond à la normale expression par rapport aux valeurs de l'indice, qui peuvent être plus rapides que balayage de la collection. D'autres optimisations peuvent se produire si la régulière expression est une "expression préfixe", ce qui signifie que tout le potentiel les matchs commencent avec la même chaîne. Cela permet à MongoDB de construire un "range" à partir de ce préfixe et ne correspondent qu'à ces valeurs de la indice qui se situent dans cette fourchette.

une expression régulière est une "expression de préfixe" si elle commence par un caret (^) ou un ancrage à gauche (\A), suivie d'une chaîne de simples symbole. Par exemple, l'expression régulière /^abc.*/ sera optimisé par la correspondant seulement à l'encontre des valeurs de l'indice commençant par abc.

en Outre, alors que /^a/, /^a.*/, et /^a.*$/ équivalent match les cordes, elles ont des caractéristiques de performance différentes. L'ensemble de ces expressions l'utilisation d'un index si un index approprié existe; cependant, /^a.*/ et /^a.*$/ sont plus lents. /^a/ peut arrêter de scanner après correspondant au préfixe.

92
répondu chridam 2018-04-23 12:54:43

j'ai eu un scénario similaire, mais dans mon cas la chaîne de caractères n'est pas un attribut de premier niveau. C'est à l'intérieur d'un objet. Ici je ne pouvais pas trouver une réponse convenable. Alors j'ai pensé partager ma solution avec vous tous(espérons que cela aidera n'importe qui avec un type similaire de problème).

Parent Collection 

{
"Child":
{
"name":"Random Name",
"Age:"09"
}
}

Ex: si nous avons besoin d'obtenir seulement des collections que 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
répondu Udara Gunathilake 2017-06-15 09:14:34

une mise à jour sur Mongo 4.0, il devient plus facile et plus fluide:

find({name: { $gt: 40 }}, function(err, posts){
    res.render('blog', {posts:posts}); // your code here
});
0
répondu celerno 2018-08-04 08:22:32