sql >> Base de Datos >  >> NoSQL >> MongoDB

Promover subcampos al nivel superior en la proyección sin enumerar todas las claves

Con MongoDB 3.4 puede usar $objectToArray y $arrayToObject con $replaceRoot para cambiar esto:

db.wish.aggregate([
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": {
        "$concatArrays": [
          [{ "k": "a", "v": "$a" }],
          { "$objectToArray": "$z" }
        ]
      }
    }
  }}
])

O incluso este largo conjuro sin siquiera especificar el "a" propiedad:

db.wish.aggregate([
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": {
        "$reduce": {
          "input": {
            "$filter": {
              "input": { "$objectToArray": "$$ROOT" },
              "as": "r",
              "cond": { "$ne": [ "$$r.k", "_id" ] }
            }
          },
          "initialValue": [],
          "in": {
            "$concatArrays": [
              "$$value",
              { "$cond": {
                "if": {  "$gt": [ "$$this.v", {} ] },
                "then": { "$objectToArray": "$$this.v" },
                "else": ["$$this"]
              }}
            ]
          }  
        } 
      }
    }
  }}
])  

Ambos producen:

{ "a" : 1, "b" : 2, "c" : 3 }

El divertido uso de $concatArrays no debería ser necesario en versiones futuras ya que habrá un $mergeObjects operador que lo hará un poco más limpio.

Pero básicamente puede hacer lo mismo en el código del cliente de manera bastante simple. Por ejemplo, en JavaScript para el shell:

db.wish.find().map( doc => (
  Object.assign({ a: doc.a }, doc.z )
))

O la versión sin el "a" de nuevo:

db.wish.find().map( doc => 
  Object.keys(doc).filter(k => k !== '_id').map(k => 
   ( typeof(doc[k]) === "object" ) ? 
     Object.keys(doc[k]).map(i => ({ [i]: doc[k][i] }))
       .reduce((acc, curr) => Object.assign(acc,curr),{})
     : { [k]: doc[k] }
  ).reduce((acc,curr) => Object.assign(acc,curr),{})
)

Produce la misma salida

{ "a" : 1, "b" : 2, "c" : 3 }