MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Mongo Query Nested Field Values ​​avec des clés parentes inconnues à deux niveaux

La réduction de carte vous permet de traiter des clés nommées, mais l'agrégation est la voie à suivre pour des requêtes efficaces.

Vous devez modéliser les données sous forme de tableau de documents intégrés pour le cadre d'agrégation.

Je vous ai proposé deux options. Vous pouvez les tester pour votre ensemble de données et voir lequel fonctionne le mieux pour vous.

Quelque chose comme

"v":[
  {
    "minute":1,
    "seconds":[
      {
        "second":54,
        "data":{
         "field1":7.373158,
         "entry_id":4635,
         "field3":0.19,
         "field2":88
       }
      }
    ]
  },
  {
    "minute":2,
    "seconds":...
  }
]

Désormais, vous pouvez facilement interroger les éléments qui ont une lecture de capteur :"field1">2.

db.col.aggregate(
  [{"$match":{"v.seconds.data.field1":{"$gt":2}}},
   {"$unwind":"$v"}, 
   {"$match":{"v.seconds.data.field1":{"$gt":2}}},
   {"$unwind":"$v.seconds"}, 
   {"$match":{"v.seconds.data.field1":{"$gt":2}}},
   {"$project":{"data":"$v.seconds.data"}}]
)

Alternativement, vous pouvez diviser les documents par minute. Quelque chose comme

"v":[
  {
    "second":1,
    "data":{
       "field1":7.373158,
       "entry_id":4635,
       "field3":0.19,
       "field2":88
     }
  },
  {
     "second":2,
     "data":...
  }
]

Vous pouvez maintenant interroger comme (avec index sur v.data.field1)

db.col.aggregate(
  [{"$match":{"v.data.field1":{"$gt":2}}},
   {"$unwind":"$v"}, 
   {"$match":{"v.data.field1":{"$gt":2}}},
   {"$project":{"data":"$v.data"}}]
)

Vous pouvez interroger les éléments qui ont une lecture de capteur :"field1">2 et "field3">5

Utilisation de la première structure

db.col.aggregate(
  [{"$match":{"v":{"$elemMatch":{"seconds": {$elemMatch:{"field1":{$gt":2},"field3":{$gt":5}}}}}}},
  {"$unwind":"$v"}, 
    {"$match":{"v.seconds": {$elemMatch:{"field1":{$gt":2},"field3":{$gt":5}}}}},
  {"$unwind":"$v.seconds"}, 
  {"$project":{"data":"$v.seconds.data"}}]
)

Utilisation de la seconde structure

db.col.aggregate(
  [{"$match":{"v.data":{$elemMatch:{"field1":{$gt":2},"field3":{$gt":5}}}}},
  {"$unwind":"$v"}, 
  {"$match":{"v.data.field1":{"$gt":2},"v.data.field3":{"$gt":5} }},
  {"$project":{"data":"$v.data"}}]
)

Mongo Mise à jour 3.6

$match avec $expr qui accepte l'expression d'agrégation.

$gt > 0 - expression d'agrégation pour vérifier où la somme de tous les critères de secondes correspondants dans une minute est supérieure à 0

$objectToArray pour convertir les clés nommées en paire clé-valeur suivie de $filter secondes sur les critères d'entrée et sortie du nombre d'enregistrements de secondes correspondants.

db.testcol.aggregate(
{"$match":{
  "$expr":{
    "$gt":[
      {"$sum":{
        "$map":{
          "input":{"$objectToArray":"$v"},
          "as":"secondsofminute",
          "in":{
            "$size":{
              "$filter":{
                "input":{"$objectToArray":"$$secondsofminute.v"},
                "as":"seconds",
                "cond":{"$gt":["$$seconds.v.field2",2]}
              }
            }
          }
        }
      }},
    0]
  }
}})

Mongo Update 3.4 - Remplacer $expr avec $redact

db.col.aggregate(
 {"$redact":{
  "$cond":{
    "if":{
      "$gt":[
        {"$sum":{
          "$map":{
            "input":{"$objectToArray":"$v"},
            "as":"secondsofminute",
            "in":{
              "$size":{
                "$filter":{
                  "input":{"$objectToArray":"$$secondsofminute.v"},
                  "as":"seconds",
                  "cond":{"$gt":["$$seconds.v.field2",2]}
                }
              }
            }
          }
        }},
        0]
    },
   "then":"$$KEEP",
   "else":"$$PRUNE"
  }
}})