รวมฟิลด์ที่มีอยู่ทั้งหมดและเพิ่มฟิลด์ใหม่ลงในเอกสาร


123

ฉันต้องการกำหนดขั้นตอนการรวมโครงการ $ ซึ่งฉันสามารถสั่งให้เพิ่มฟิลด์ใหม่และรวมฟิลด์ที่มีอยู่ทั้งหมดโดยไม่ต้องแสดงรายการฟิลด์ที่มีอยู่ทั้งหมด

เอกสารของฉันมีลักษณะดังนี้มีหลายช่อง:

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

ฉันต้องการทำการรวมแบบนี้:

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

มีบางอย่างเช่นคีย์เวิร์ด "รวมฟิลด์ทั้งหมด" ที่ฉันสามารถใช้ในกรณีนี้หรือวิธีอื่นเพื่อหลีกเลี่ยงการแสดงรายการทุกฟิลด์แยกกัน


1
คุณลักษณะนี้จะมาในรุ่นหลักถัดไป 2.6 คุณสามารถทดลองใช้ในสาขา dev ที่ไม่เสถียร - ใช้ "$$ ROOT" เพื่ออ้างถึงเอกสารขาเข้าทั้งหมด ดูรายละเอียดในตั๋วนี้: jira.mongodb.org/browse/SERVER-5916
Asya Kamsky

1
ปัญหานี้ยังถูกยกขึ้นที่stackoverflow.com/questions/20497499/…พร้อมคำตอบอื่น ๆ ที่มีประโยชน์และแตกต่างกัน
Vince Bowdren

คำตอบ:


168

ใน 4.2+ คุณสามารถใช้$setตัวดำเนินการไปป์ไลน์การรวมซึ่งไม่ใช่สิ่งอื่นใดนอกจากนามแฝงที่$addFieldsเพิ่มใน 3.4

$addFieldsเตจเทียบเท่ากับส$projectเตจที่ระบุฟิลด์ที่มีอยู่ทั้งหมดในเอกสารอินพุตอย่างชัดเจนและเพิ่มฟิลด์ใหม่

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

2
มีความคิดอย่างไรในการใช้งานในไดรเวอร์ C #? ดูเหมือนว่าจะไม่มีอยู่จริง
Homam

ฉันไม่คุ้นเคยกับไดรเวอร์ C # แต่$addFieldsเป็นของใหม่ใน MongoDB 3.4 ซึ่งรองรับโดยไดรเวอร์ C # เวอร์ชัน 2.5+
styvane

ฉันได้ค้นหาวิธีการทำสิ่งนี้ในไดรเวอร์ C # และจนถึงตอนนี้ดูเหมือนว่าวิธีการทำจะใช้อะไรเช่นIAggregateFluent<TResult>.AppendStage(new JsonPipelineStageDefinition<TInput, TOutput>("{ $addFields : { myField: 'myValue' }}")
sboisse

4
ฉันค้นพบว่ามันสามารถแทนที่ฟิลด์ได้หากคุณระบุชื่อฟิลด์เดียวกัน
CME64

79

คุณสามารถใช้$$ ROOTเพื่ออ้างอิงเอกสารราก เก็บฟิลด์ทั้งหมดของเอกสารนี้ไว้ในฟิลด์และพยายามรับหลังจากนั้น (ขึ้นอยู่กับระบบไคลเอนต์ของคุณ: Java, C ++, ... )

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

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

17
แต่นี้จะสร้าง doc ฝังตัวที่เรียกว่าdocumentตัวเลือกในการสร้างหนึ่งรวมเอกสารจะได้รับดีกว่า ...
อเล็กซานเด Suraphel

2
มีใครทราบวิธีแก้ปัญหาในการส่งผ่านคู่ค่าคีย์ทั้งหมดโดยไม่ต้องสร้างเอกสารฝังตัวหรือไม่?
ugotchi

11
กลั้นลมหายใจของคุณ. MongoDB 3.4 จะมาพร้อมกับขั้นตอนการรวม $ addFieldsที่ทำเพียงแค่นี้ ดูstackoverflow.com/a/24557029/4653485
Jérôme

นี่ดูเหมือนจะเป็นวิธีแก้ปัญหาที่ดีที่สุดในปัจจุบันเท่าที่จะทำได้ (อย่างน้อยก็ใน JS) จากนั้นใช้ตัวดำเนินการกระจายเพื่อสร้างออบเจ็กต์ดั้งเดิมของคุณใหม่ด้วยสิ่งที่custom_fieldแนบมาใหม่ const newObj = { ...result.document, custom_field: result.custom_field }
ffritz

7

>>> มีคำหลัก "รวมทุกช่อง" ที่ฉันสามารถใช้ในกรณีนี้หรือวิธีแก้ปัญหาอื่น

น่าเสียดายที่ไม่มีตัวดำเนินการที่จะ "รวมฟิลด์ทั้งหมด" ในการดำเนินการรวม เหตุผลเดียวคือทำไมเนื่องจากการรวมส่วนใหญ่สร้างขึ้นเพื่อจัดกลุ่ม / คำนวณข้อมูลจากเขตข้อมูลการรวบรวม (ผลรวมค่าเฉลี่ย ฯลฯ ) และส่งคืนฟิลด์ทั้งหมดของคอลเล็กชันไม่ใช่วัตถุประสงค์โดยตรง


... เนื่องจากการรวมส่วนใหญ่สร้างขึ้นเพื่อจัดกลุ่ม / คำนวณข้อมูลจากฟิลด์รวบรวม ...คำตอบที่ดีที่สุดในความเป็นจริง!
felipsmartins

1
คุณมีคอลเล็กชันที่postsมี _id ชื่อเนื้อหาชอบช่อง ช่องไลค์คืออาร์เรย์ของผู้ใช้ _id ที่ชอบโพสต์ คุณจะแสดงรายการโพสต์ทั้งหมดด้วย _id, title, body, likeCount ได้อย่างไร การส่งคืนฟิลด์ทั้งหมดเป็นจุดประสงค์โดยตรงในกรณีนี้
doc_id

3

ในเวอร์ชัน 2.6.4 Mongo DB ไม่มีคุณสมบัติดังกล่าวสำหรับ$projectไปป์ไลน์การรวม จากเอกสารสำหรับ$project:

ส่งผ่านเอกสารที่มีเฉพาะฟิลด์ที่ระบุไปยังขั้นตอนถัดไปในไปป์ไลน์ ฟิลด์ที่ระบุอาจเป็นฟิลด์ที่มีอยู่จากเอกสารอินพุตหรือฟิลด์ที่คำนวณใหม่

และ

โดยค่าเริ่มต้นฟิลด์ _id จะรวมอยู่ในเอกสารผลลัพธ์ ในการรวมฟิลด์อื่น ๆ จากเอกสารอินพุตในเอกสารเอาต์พุตคุณต้องระบุการรวมใน $ project อย่างชัดเจน


2

ในการเพิ่มฟิลด์ใหม่ลงในเอกสารของคุณคุณสามารถใช้ได้ $addFields

จากเอกสาร

และทุกช่องในเอกสารของคุณคุณสามารถใช้ $$ROOT

db.collection.aggregate([

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

0

ตามการตอบกลับของ @Deka สำหรับไดรเวอร์ c # mongodb 2.5 คุณจะได้รับเอกสารที่จัดกลุ่มพร้อมคีย์ทั้งหมดดังต่อไปนี้

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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.