Sertakan semua bidang yang ada dan tambahkan bidang baru ke dokumen

123

Saya ingin menentukan tahap agregasi $ project di mana saya dapat menginstruksikannya untuk menambahkan bidang baru dan menyertakan semua bidang yang ada, tanpa harus mencantumkan semua bidang yang ada.

Dokumen saya terlihat seperti ini, dengan banyak bidang:

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

Saya ingin membuat operasi agregasi seperti ini:

[
    {
        $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...
]

Apakah ada sesuatu seperti kata kunci "sertakan semua bidang" yang dapat saya gunakan dalam kasus ini, atau cara lain untuk menghindari keharusan mencantumkan setiap bidang secara terpisah?

samuelluis.dll
sumber
1
Fitur ini akan hadir di rilis utama berikutnya 2.6. Anda dapat mencobanya di cabang dev yang tidak stabil - gunakan "$$ ROOT" untuk merujuk ke seluruh dokumen yang masuk. Lihat detail di tiket ini: jira.mongodb.org/browse/SERVER-5916
Asya Kamsky
1
Masalah ini juga diangkat di stackoverflow.com/questions/20497499/… , dengan beberapa jawaban lain yang berguna dan berbeda.
Vince Bowdren

Jawaban:

168

Di 4.2+, Anda dapat menggunakan $setoperator pipeline agregasi yang tidak lain adalah alias untuk $addFieldsditambahkan di 3.4

The $addFieldspanggung adalah setara dengan $projecttahap yang secara eksplisit menentukan semua bidang yang ada dalam dokumen input dan menambahkan bidang baru.

db.collection.aggregate([
    { "$addFields": { "custom_field": "$obj.obj_field1" } }
])
styvane
sumber
2
Ada ide bagaimana menggunakannya di driver C #? tampaknya itu tidak ada
Homam
Saya tidak terbiasa dengan driver C # tetapi $addFieldsbaru di MongoDB 3.4 yang didukung oleh driver C # versi
2.5+
Saya telah mencari cara untuk melakukan ini di driver C #, dan sejauh ini sepertinya cara untuk melakukannya akan menggunakan sesuatu sepertiIAggregateFluent<TResult>.AppendStage(new JsonPipelineStageDefinition<TInput, TOutput>("{ $addFields : { myField: 'myValue' }}")
sboisse
4
Saya menemukan bahwa itu bahkan dapat mengganti bidang jika Anda menentukan nama bidang yang sama
CME64
79

Anda dapat menggunakan $$ ROOT untuk mereferensikan dokumen root. Simpan semua bidang dokumen ini dalam satu bidang dan coba untuk mendapatkannya setelah itu (tergantung pada sistem klien Anda: Java, C ++, ...)

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

        }
    },
    ... //group, match, and whatever...
]
Deka
sumber
17
Tapi ini akan membuat dokumen yang disematkan yang disebut documentopsi untuk membuat satu dokumen gabungan akan lebih baik ...
Alexander Suraphel
2
Adakah yang tahu tentang solusi untuk melewati semua pasangan nilai kunci tanpa membuat dokumen yang disematkan?
ugotchi
11
Tahan nafasmu. MongoDB 3.4 akan hadir dengan tahap agregasi $ addFields yang melakukan hal ini. Lihat stackoverflow.com/a/24557029/4653485 .
Jérôme
Ini tampaknya menjadi solusi terbaik saat ini, karena Anda dapat (setidaknya di JS) kemudian menggunakan operator penyebaran untuk membangun kembali objek asli Anda dengan yang baru custom_fieldterpasang. const newObj = { ...result.document, custom_field: result.custom_field }
ffritz
7

>>> Ada sesuatu seperti kata kunci "sertakan semua bidang" yang dapat saya gunakan dalam kasus ini atau solusi lain?

Sayangnya, tidak ada operator yang "menyertakan semua kolom" dalam operasi agregasi. Satu-satunya alasan, mengapa, karena agregasi sebagian besar dibuat untuk mengelompokkan / menghitung data dari bidang koleksi (jumlah, rata-rata, dll.) Dan mengembalikan semua bidang kumpulan bukan tujuan langsung.

Victoria Malaya
sumber
... karena agregasi sebagian besar dibuat untuk mengelompokkan / menghitung data dari kolom koleksi ... Jawaban terbaik sebenarnya!
felipsmartins
1
Anda memiliki koleksi postsdengan _id, judul, badan, bidang suka. Bidang suka adalah larik pengguna _id yang menyukai pos. Bagaimana Anda bisa membuat daftar semua posting dengan semua _id, title, body, likeCount? Mengembalikan semua bidang adalah tujuan langsung dalam kasus ini.
doc_id
3

Mulai versi 2.6.4, Mongo DB tidak memiliki fitur seperti itu untuk $projectpipeline agregasi. Dari dokumen untuk $project:

Meneruskan dokumen dengan hanya bidang yang ditentukan ke tahap berikutnya dalam pipeline. Bidang yang ditentukan dapat berupa bidang yang ada dari dokumen input atau bidang yang baru dihitung.

dan

Bidang _id, secara default, disertakan dalam dokumen keluaran. Untuk memasukkan field lain dari dokumen masukan ke dalam dokumen keluaran, Anda harus secara eksplisit menentukan penyertaan dalam $ project.

Ghopper21
sumber
2

Untuk menambahkan bidang baru ke dokumen Anda, Anda dapat menggunakan $addFields

dari dokumen

dan ke semua bidang di dokumen Anda, Anda dapat menggunakan $$ROOT

db.collection.aggregate([

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

menurut balasan @Deka, untuk c # mongodb driver 2.5 Anda bisa mendapatkan dokumen yang dikelompokkan dengan semua kunci seperti di bawah ini;

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);
mr.byte
sumber