Mevcut tüm alanları dahil edin ve belgeye yeni alanlar ekleyin


123

Var olan tüm alanları listelemeye gerek kalmadan yeni bir alan eklemesini ve mevcut tüm alanları dahil etmesini isteyebileceğim bir $ proje toplama aşaması tanımlamak istiyorum.

Belgem birçok alanla şöyle görünüyor:

{
    obj: {
        obj_field1: "hi",
        obj_field2: "hi2"
    },
    field1: "a",
    field2: "b",
    ...
    field26: "z"
}

Bunun gibi bir toplama işlemi yapmak istiyorum:

[
    {
        $project: {
            custom_field: "$obj.obj_field1",
            //the next part is that I don't want to do
            field1: 1,
            field2: 1,
            ...
            field26: 1
        }
    },
    ... //group, match, and whatever...
]

Bu durumda kullanabileceğim "tüm alanları içer" anahtar kelimesi gibi bir şey var mı, yoksa her alanı ayrı ayrı listelemek zorunda kalmamak için başka bir yol var mı?


1
Bu özellik bir sonraki ana sürüm 2.6'da geliyor. Kararsız geliştirme dalında deneyebilirsiniz - gelen belgenin tamamına başvurmak için "$$ ROOT" kullanın. Bu biletteki
Asya

1
Bu sorun ayrıca , diğer bazı yararlı ve farklı yanıtlarla birlikte stackoverflow.com/questions/20497499/… adresinde de gündeme getirilmiştir .
Vince Bowdren

Yanıtlar:


168

4.2+ sürümünde, 3.4'e eklenecek $setbir takma addan başka bir şey olmayan toplama işlem hattı operatörünü kullanabilirsiniz.$addFields

$addFieldsEvre bir eşdeğerdir $projectaçıkça giriş belgelerinde mevcut tüm alanları belirtir ve yeni alanlar ekler evre.

db.collection.aggregate([
    { "$addFields": { "custom_field": "$obj.obj_field1" } }
])

2
C # sürücüsünde nasıl kullanılacağı hakkında bir fikriniz var mı? yok gibi görünüyor
Homam

C # sürücüsüne aşina değilim, ancak C # sürücü sürümü$addFields
2.5+

C # sürücüsü bunu yapmanın bir yolu arıyor edilmiş ve bugüne kadar bunun gibi bir şey kullanarak olurdu yapmak için bir yol gibi görünüyorIAggregateFluent<TResult>.AppendStage(new JsonPipelineStageDefinition<TInput, TOutput>("{ $addFields : { myField: 'myValue' }}")
sboisse

4
Aynı alan adını belirtirseniz bir alanı bile değiştirebileceğini keşfettim
CME64

79

Kök belgeye başvurmak için $$ ROOT'u kullanabilirsiniz . Bu belgenin tüm alanlarını bir alanda tutun ve bundan sonra almaya çalışın (istemci sisteminize bağlı olarak: Java, C ++, ...)

 [
    {
        $project: {
            custom_field: "$obj.obj_field1",
            document: "$$ROOT"

        }
    },
    ... //group, match, and whatever...
]

17
Ancak bu, birleştirilmiş bir belge oluşturma documentseçeneği adı verilen gömülü bir belge oluşturacak daha güzel olurdu ...
Alexander Suraphel

2
Gömülü belgeyi oluşturmadan tüm anahtar değer çiftlerinden geçmenin çözümünü bilen var mı?
ugotchi

11
Nefesini tut. MongoDB 3.4 tam da bunu yapan $ addFields toplama aşamasıyla gelecek . Stackoverflow.com/a/24557029/4653485 adresine bakın .
Jérôme

Bu mevcut en iyi çözüm gibi görünüyor, (en azından JS'de) daha sonra orijinal nesnenizi yeni custom_fieldeklenmiş olarak yeniden oluşturmak için yayma operatörünü kullanın . const newObj = { ...result.document, custom_field: result.custom_field }
ffritz

7

>>> Bu durumda veya başka bir çözümde kullanabileceğim "tüm alanları içer" anahtar kelimesi gibi bir şey var mı?

Ne yazık ki, toplama işlemine "tüm alanları dahil edecek" bir operatör yoktur. Bunun tek nedeni, çünkü toplama çoğunlukla toplama alanlarındaki verileri (toplam, ortalama, vb.) Gruplamak / hesaplamak ve koleksiyonun tüm alanlarını döndürmek için oluşturulduğu için doğrudan amaç değildir.


... çünkü toplama çoğunlukla toplama alanlarındaki verileri gruplamak / hesaplamak için oluşturulur ... Aslında en iyi yanıt!
felipsmartins

1
posts_id, başlık, gövde, beğeni alanları olan bir koleksiyonunuz var . Beğeni alanı, gönderiyi beğenen bir kullanıcı _id dizisidir. Tüm _id, title, body, likeCount gibi tüm gönderileri nasıl listeleyebilirsiniz? Bu durumda tüm alanları geri döndürmek doğrudan bir amaçtır.
doc_id

3

2.6.4 sürümünden itibaren, Mongo DB, $projecttoplama işlem hattı için böyle bir özelliğe sahip değildir . Gönderen docs için $project:

Yalnızca belirtilen alanlara sahip belgeler boyunca boru hattındaki bir sonraki aşamaya geçer. Belirtilen alanlar, giriş belgelerinden veya yeni hesaplanan alanlardan mevcut alanlar olabilir.

ve

_İd alanı varsayılan olarak çıktı belgelerine dahil edilir. Girdi belgelerindeki diğer alanları çıktı belgelerine dahil etmek için $ projesine dahil etmeyi açıkça belirtmeniz gerekir.


2

Belgenize yeni alanlar eklemek için kullanabilirsiniz $addFields

belgelerden

ve belgenizdeki tüm alanlarda kullanabilirsiniz $$ROOT

db.collection.aggregate([

{ "$addFields": { "custom_field": "$obj.obj_field1" } },
{ "$group": {
        _id : "$field1",
        data: { $push : "$$ROOT" }
    }}
])

0

@Deka cevabına göre, c # mongodb sürücüsü 2.5 için, aşağıdaki gibi tüm tuşlarla gruplanmış belgeyi alabilirsiniz;

var group = new BsonDocument
{
 { "_id", "$groupField" },
 { "_document", new BsonDocument { { "$first", "$$ROOT" } } }
};

ProjectionDefinition<BsonDocument> projection = new BsonDocument{{ "document", "$_document"}};
var result = await col.Aggregate().Group(group).Project(projection).ToListAsync();

// For demo first record 
var fistItemAsT = BsonSerializer.Deserialize<T>(result.ToArray()[0]["document"].AsBsonDocument);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.