2

Voici le modèle de mon article.Comment inclure un tableau vide lors du filtrage d'un tableau

const itemSchema = new Schema({ 
    name: String, 
    category: String, 
    occupied: [Number], 
    active: { type: Boolean, default: true }, 
}); 

Je veux filtrer le tableau 'occupé'. J'utilise donc le champ agrégé et déroulé 'occupé'.

J'applique donc une requête de correspondance. Et groupe par _id. Mais si le tableau 'occupé' filtré est vide, l'élément disparaît.

Voici mon code

Item.aggregate([ 
    { $match: { 
    active: true 
    }}, 
    { $unwind: 
    "$occupied", 
    }, 
    { $match: { $and: [ 
    { occupied: { $gte: 100 }}, 
    { occupied: { $lt: 200 }} 
    ]}}, 
    { $group : { 
    _id: "$_id", 
    name: { $first: "$name"}, 
    category: { $first: "$category"}, 
    occupied: { $addToSet : "$occupied" } 
    }} 
], (err, items) => { 
    if (err) throw err; 
    return res.json({ data: items }); 
}); 

Voici les données exemple de

{ 
    "_id" : ObjectId("59c1bced987fa30b7421a3eb"), 
    "name" : "printer1", 
    "category" : "printer", 
    "occupied" : [ 95, 100, 145, 200 ], 
    "active" : true 
}, 
{ 
    "_id" : ObjectId("59c2dbed992fb91b7421b1ad"), 
    "name" : "printer2", 
    "category" : "printer", 
    "occupied" : [ ], 
    "active" : true 
} 

Le résultat ci-dessus requête

[ 
    { 
    "_id" : ObjectId("59c1bced987fa30b7421a3eb"), 
    "name" : "printer1", 
    "category" : "printer", 
    "occupied" : [ 100, 145 ], 
    "active" : true 
    } 
] 

et le résultat que je veux

[ 
    { 
    "_id" : ObjectId("59c1bced987fa30b7421a3eb"), 
    "name" : "printer1", 
    "category" : "printer", 
    "occupied" : [ 100, 145 ], 
    "active" : true 
    }, 
    { 
    "_id" : ObjectId("59c2dbed992fb91b7421b1ad"), 
    "name" : "printer2", 
    "category" : "printer", 
    "occupied" : [ ], 
    "active" : true 
    } 
] 

comment pourrais-je faire cela ??

Merci d'avance.

+1

Bien qu'il aurait été préférable que vous trouviez l'option "pretty print" pour les échantillons de données (maintenant joli), en fournissant un exemple clair des données que vous avez, le résultat que vous voulez et la tentative que vous avez Beaucoup de gens pourraient apprendre de vous comment poser une question ici. C'est exactement comme cela que les questions devraient être posées. Au point et complet. Continuez. –

+0

@NeilLunn Merci pour votre commentaire. Je garderai ça à l'esprit. – 125487

Répondre

0

Dans la forme la plus simple, vous le gardez simplement en n'utilisant pas $unwind en premier lieu. Vos conditions appliquées impliquent que vous recherchez "l'ensemble unique" de correspondances à des valeurs spécifiques.

Pour cela, vous utilisez à la place $filter, et un « opérateur set » comme $setUnion pour réduire les valeurs d'entrée à un « ensemble » en premier lieu:

Item.aggregate([ 
    { "$match": { "active": true } }, 
    { "$project": { 
    "name": 1, 
    "category": 1, 
    "occupied": { 
     "$filter": { 
     "input": { "$setUnion": [ "$occupied", []] }, 
     "as": "o", 
     "cond": { 
      "$and": [ 
      { "$gte": ["$$o", 100 ] }, 
      { "$lt": ["$$o", 200] } 
      ] 
     } 
     } 
    } 
    }} 
], (err, items) => { 
    if (err) throw err; 
    return res.json({ data: items }); 
}); 

Tous deux ont été autour depuis MongoDB v3, donc C'est une pratique assez courante de faire les choses de cette façon.

Si pour une raison quelconque vous utilisez encore MongoDB 2.6, vous pouvez appliquer à la place $map et $setDifference:

Item.aggregate([ 
    { "$match": { "active": true } }, 
    { "$project": { 
    "name": 1, 
    "category": 1, 
    "occupied": { 
     "$setDifference": [ 
     { "$map": { 
      "input": "$occupied", 
      "as": "o", 
      "in": { 
      "$cond": { 
       "if": { 
       "$and": [ 
        { "$gte": ["$$o", 100 ] }, 
        { "$lt": ["$$o", 200] } 
       ] 
       }, 
       "then": "$$o", 
       "else": false 
      } 
      } 
     }}, 
     [false] 
     ] 
    } 
    }} 
], (err, items) => { 
    if (err) throw err; 
    return res.json({ data: items }); 
}); 

Il est le même résultat « ensemble unique » en tirant le tableau à part, filtrer les éléments et mettre retour avec $addToSet. La différence étant que c'est beaucoup plus efficace, et conserve (ou produit) un tableau vide sans aucun problème.

+0

J'utilise MongoDB 2.6 maintenant. Mais je vais mettre à jour v3 et essayer votre solution. Merci pour une explication détaillée. – 125487

+0

@ 125487 Comme indiqué dans la réponse, la deuxième approche utilise des opérateurs compatibles avec MongoDB 2.6. Je devrais noter que si vous vouliez le soutien officiel, alors [cette version est passée en fin de vie pour le support] (https://www.mongodb.com/support-policy), donc la mise à niveau est probablement dans votre meilleur intérêt. –

+0

J'ai mis à jour MongoDB à v3.4. et votre première approche fonctionne parfaitement. Merci pour le commentaire. – 125487