MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Promuovi i sottocampi al livello più alto nella proiezione senza elencare tutte le chiavi

Con MongoDB 3.4 puoi usare $objectToArray e $arrayToObject con $replaceRoot per cambiarlo:

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

O anche questo lungo incantesimo senza nemmeno specificare il "a" proprietà:

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"]
              }}
            ]
          }  
        } 
      }
    }
  }}
])  

Entrambi producono:

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

L'uso divertente di $concatArrays non dovrebbe essere necessario nelle versioni future poiché ci sarà un $mergeObjects operatore che lo renderà un po' più pulito.

Ma in pratica puoi semplicemente fare la stessa cosa nel codice client in modo abbastanza semplice. Ad esempio in JavaScript per la shell:

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

O la versione senza il "a" ancora:

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 lo stesso output

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