Mongoose (mongodb) ชุดใส่?


114

ทำ พังพอน v3.6 +แทรกสนับสนุนชุดตอนนี้หรือไม่ ฉันค้นหามาสองสามนาทีแล้ว แต่สิ่งที่ตรงกับคำค้นหานี้มีอายุสองสามปีและคำตอบคือไม่ชัดเจน

แก้ไข:

Model.create()สำหรับการอ้างอิงในอนาคตคำตอบคือการใช้งานcreate()ยอมรับอาร์เรย์เป็นอาร์กิวเมนต์แรกดังนั้นคุณสามารถส่งเอกสารของคุณไปแทรกเป็นอาร์เรย์ได้

ดูเอกสาร Model.create ()


ดูคำตอบของคำถามก่อนหน้านี้
JohnnyHK

ขอบคุณ นั่นคือสิ่งที่ฉันพบหลังจากโพสต์
Geuis

@Geuis โปรดเพิ่มการแก้ไขของคุณเป็นคำตอบและยอมรับเพื่อแก้ไขคำถามของคุณ
Filip Dupanović


Model.create () ทำงานช้าและหากคุณกำลังพิจารณาแทรกเอกสารจำนวนมากควรใช้แนวทางนี้แทน
Lucio Paiva

คำตอบ:


162

Model.create () เทียบกับ Model.collection.insert (): แนวทางที่เร็วกว่า

Model.create()เป็นวิธีที่ไม่ดีในการทำเม็ดมีดหากคุณต้องรับมือกับสินค้าจำนวนมาก มันจะช้ามาก ในกรณีนี้คุณควรใช้Model.collection.insertซึ่งมีประสิทธิภาพดีกว่ามาก Model.create()จะผิดพลาดขึ้นอยู่กับขนาดของกลุ่ม! พยายามด้วยเอกสารเป็นล้านไม่มีโชค ใช้Model.collection.insertเวลาเพียงไม่กี่วินาที

Model.collection.insert(docs, options, callback)
  • docs คืออาร์เรย์ของเอกสารที่จะแทรก
  • optionsเป็นอ็อบเจ็กต์คอนฟิกูเรชันที่เป็นทางเลือกโปรดดูเอกสาร
  • callback(err, docs)จะถูกเรียกหลังจากเอกสารทั้งหมดได้รับการบันทึกหรือเกิดข้อผิดพลาด เมื่อประสบความสำเร็จ docs คืออาร์เรย์ของเอกสารที่ยังคงอยู่

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

ตัวอย่างง่ายๆ

var Potato = mongoose.model('Potato', PotatoSchema);

var potatoBag = [/* a humongous amount of potato objects */];

Potato.collection.insert(potatoBag, onInsert);

function onInsert(err, docs) {
    if (err) {
        // TODO: handle error
    } else {
        console.info('%d potatoes were successfully stored.', docs.length);
    }
}

อัพเดท 2019/06/22 : แม้จะยังสามารถใช้เพียงแค่ปรับก็ถูกเลิกในความโปรดปรานของinsert() insertMany()พารามิเตอร์เหมือนกันทุกประการดังนั้นคุณสามารถใช้มันเป็นการทดแทนแบบดร็อปอินและทุกอย่างควรทำงานได้ดี (ค่าที่ส่งคืนจะแตกต่างกันเล็กน้อย แต่คุณอาจไม่ได้ใช้มันอยู่ดี)

การอ้างอิง


1
groups.google.com/forum/#!topic/mongoose-orm/IkPmvcd0kdsพูดได้ทั้งหมดจริงๆ
arcseldon

โปรดยกตัวอย่างกับพังพอน
Steve K

15
เนื่องจากModel.collectionต้องใช้ไดรเวอร์ Mongo โดยตรงคุณจึงสูญเสียสิ่งของพังพอนที่เป็นระเบียบทั้งหมดรวมถึงการตรวจสอบความถูกต้องและขอเกี่ยว สิ่งที่ควรทราบ Model.createสูญเสียตะขอ แต่ยังต้องผ่านการตรวจสอบความถูกต้อง ถ้าคุณต้องการทั้งหมดคุณต้องทำซ้ำและnew MyModel()
Pier-Luc Gendreau

1
@ Pier-LucGendreau คุณพูดถูก แต่มันเป็นการแลกเปลี่ยนที่คุณต้องทำเมื่อคุณเริ่มจัดการกับข้อมูลจำนวนมหาศาล
Lucio Paiva

1
โปรดระวังผู้อ่านใหม่: "การเปลี่ยนแปลงในเวอร์ชัน 2.6: ส่วนแทรก () ส่งคืนวัตถุที่มีสถานะของการดำเนินการ" ไม่มีเอกสารอีกต่อไป
Mark Ni

117

Mongoose 4.4.0 รองรับการแทรกจำนวนมากแล้ว

พังพอน 4.4.0 แนะนำ --true-- .insertMany()แทรกกลุ่มด้วยวิธีการแบบ เป็นวิธีที่เร็วกว่าการวนซ้ำ.create()หรือจัดเตรียมอาร์เรย์

การใช้งาน:

var rawDocuments = [/* ... */];

Book.insertMany(rawDocuments)
    .then(function(mongooseDocuments) {
         /* ... */
    })
    .catch(function(err) {
        /* Error handling */
    });

หรือ

Book.insertMany(rawDocuments, function (err, mongooseDocuments) { /* Your callback function... */ });

คุณสามารถติดตามได้ที่:


2
ในขณะนี้วิธีนี้ไม่รองรับตัวเลือก
Amri

ขอบคุณสำหรับคำตอบ มีความคิดใดบ้างที่ควรแยกวิเคราะห์ rawDocuments ฉันได้ลองใช้กับอาร์เรย์ของวัตถุ Json และสิ่งที่ใส่เข้าไปก็มีเพียง ID เท่านั้น :(
Ondrej Tokar

4
สิ่งนี้แตกต่างกับbulkWriteอย่างไร? ดูที่นี่: stackoverflow.com/questions/38742475/…
Ondrej Tokar

insertMany ไม่ได้ผลสำหรับฉัน ฉันได้รับfatal error allocation failed. แต่ถ้าฉันใช้ collection.insert มันก็ใช้ได้ดี
จอห์น

สิ่งนี้จะใช้ได้กับสิ่งพิเศษที่พังพอนสคีมาหรือไม่? เช่นนี้จะเพิ่มข้อมูลหากไม่มีวันที่dateCreated : { type: Date, default: Date.now },
แจ็คว่างเปล่า

22

แน่นอนคุณสามารถใช้วิธีการ "สร้าง" ของพังพอนมันสามารถมีเอกสารมากมายดูตัวอย่างนี้:

Candy.create({ candy: 'jelly bean' }, { candy: 'snickers' }, function (err, jellybean, snickers) {
});

ฟังก์ชันเรียกกลับประกอบด้วยเอกสารที่แทรก คุณไม่รู้ว่าต้องแทรกกี่รายการ (ความยาวอาร์กิวเมนต์คงที่เหมือนด้านบน) เพื่อให้คุณสามารถวนซ้ำได้:

var insertedDocs = [];
for (var i=1; i<arguments.length; ++i) {
    insertedDocs.push(arguments[i]);
}

อัปเดต: ทางออกที่ดีกว่า

ทางออกที่ดีกว่าควรใช้Candy.collection.insert()แทนCandy.create()- ใช้ในตัวอย่างด้านบน - เพราะเร็วกว่า ( create()กำลังโทรModel.save()แต่ละรายการจึงช้ากว่า)

ดูเอกสาร Mongo สำหรับข้อมูลเพิ่มเติม: http://docs.mongodb.org/manual/reference/method/db.collection.insert/

(ขอบคุณarcseldon ที่ชี้ให้เห็น)


groups.google.com/forum/#!topic/mongoose-orm/IkPmvcd0kds - ขึ้นอยู่กับสิ่งที่คุณต้องการลิงก์มีตัวเลือกที่ดีกว่า
arcseldon

ไม่ได้หมายถึง{type:'jellybean'}แทน{type:'jelly bean'}เหรอ? Btw พวกประเภทแปลก ๆ คืออะไร? พวกเขาเป็นส่วนหนึ่งของ Mongoose API หรือไม่
Steve K

2
นั่นเป็นตัวเลือกการตั้งชื่อที่ไม่ถูกต้องเนื่องจากtypeโดยปกติแล้วจะสงวนไว้ใน Mongoose เพื่อกำหนด ADT ของวัตถุฐานข้อมูล
Steve K

2
@sirbenbenji ฉันเปลี่ยนแล้ว แต่มันก็เป็นตัวอย่างที่มีอยู่ในเอกสารอย่างเป็นทางการด้วย ไม่จำเป็นต้องลดคะแนนสำหรับสิ่งนี้ฉันคิดว่า
benske

1
ด้วยการระบุคุณสมบัติ .collection คุณกำลังข้ามพังพอน (การตรวจสอบความถูกต้องวิธีการ 'ก่อน' ... )
Derek

4

คุณสามารถทำการแทรกจำนวนมากโดยใช้ mongoDB shell โดยใช้การแทรกค่าในอาร์เรย์

db.collection.insert([{values},{values},{values},{values}]);

พังพอนมีวิธีในการใส่จำนวนมากหรือไม่?
SUNDARRAJAN K

1
YourModel.collection.insert()
Bill Dami

ด้วยการระบุคุณสมบัติ .collection คุณกำลังข้ามพังพอน (การตรวจสอบความถูกต้องวิธีการ 'ก่อน' ... )
Derek

นี่ไม่ใช่พังพอนและcollection.insertคำตอบดิบได้รับสองสามสัปดาห์ก่อนคำตอบนี้และอธิบายรายละเอียดเพิ่มเติม
Dan Dascalescu

4

คุณสามารถทำการแทรกจำนวนมากโดยใช้พังพอนเป็นคำตอบที่ได้คะแนนสูงสุด แต่ตัวอย่างไม่สามารถใช้งานได้ควรเป็น:

/* a humongous amount of potatos */
var potatoBag = [{name:'potato1'}, {name:'potato2'}];

var Potato = mongoose.model('Potato', PotatoSchema);
Potato.collection.insert(potatoBag, onInsert);

function onInsert(err, docs) {
    if (err) {
        // TODO: handle error
    } else {
        console.info('%d potatoes were successfully stored.', docs.length);
    }
}

อย่าใช้อินสแตนซ์สคีมาสำหรับการแทรกจำนวนมากคุณควรใช้วัตถุแผนที่ธรรมดา


คำตอบแรกไม่ผิดมันเพิ่งมีการตรวจสอบ
Luca Steeb

1
ด้วยการระบุคุณสมบัติ. collection คุณกำลังข้ามพังพอน (การตรวจสอบความถูกต้องวิธีการ 'ก่อน' ... )
Derek

4

นี่คือทั้งสองวิธีในการบันทึกข้อมูลด้วย insertMany และบันทึก

1) พังพอนบันทึกอาร์เรย์ของเอกสารด้วยinsertManyจำนวนมาก

/* write mongoose schema model and export this */
var Potato = mongoose.model('Potato', PotatoSchema);

/* write this api in routes directory  */
router.post('/addDocuments', function (req, res) {
    const data = [/* array of object which data need to save in db */];

    Potato.insertMany(data)  
    .then((result) => {
            console.log("result ", result);
            res.status(200).json({'success': 'new documents added!', 'data': result});
    })
    .catch(err => {
            console.error("error ", err);
            res.status(400).json({err});
    });
})

2) พังพอนบันทึกอาร์เรย์ของเอกสารด้วย .save()

เอกสารเหล่านี้จะบันทึกแบบขนาน

/* write mongoose schema model and export this */
var Potato = mongoose.model('Potato', PotatoSchema);

/* write this api in routes directory  */
router.post('/addDocuments', function (req, res) {
    const saveData = []
    const data = [/* array of object which data need to save in db */];
    data.map((i) => {
        console.log(i)
        var potato = new Potato(data[i])
        potato.save()
        .then((result) => {
            console.log(result)
            saveData.push(result)
            if (saveData.length === data.length) {
                res.status(200).json({'success': 'new documents added!', 'data': saveData});
            }
        })
        .catch((err) => {
            console.error(err)
            res.status(500).json({err});
        })
    })
})

3

ดูเหมือนว่าการใช้พังพอนจะมีการ จำกัด เอกสารมากกว่า 1,000 รายการเมื่อใช้

Potato.collection.insert(potatoBag, onInsert);

คุณสามารถใช้ได้:

var bulk = Model.collection.initializeOrderedBulkOp();

async.each(users, function (user, callback) {
    bulk.insert(hash);
}, function (err) {
    var bulkStart = Date.now();
    bulk.execute(function(err, res){
        if (err) console.log (" gameResult.js > err " , err);
        console.log (" gameResult.js > BULK TIME  " , Date.now() - bulkStart );
        console.log (" gameResult.js > BULK INSERT " , res.nInserted)
      });
});

แต่นี่เร็วกว่าเกือบสองเท่าเมื่อทดสอบกับเอกสาร 10,000 รายการ:

function fastInsert(arrOfResults) {
var startTime = Date.now();
    var count = 0;
    var c = Math.round( arrOfResults.length / 990);

    var fakeArr = [];
    fakeArr.length = c;
    var docsSaved = 0

    async.each(fakeArr, function (item, callback) {

            var sliced = arrOfResults.slice(count, count+999);
            sliced.length)
            count = count +999;
            if(sliced.length != 0 ){
                    GameResultModel.collection.insert(sliced, function (err, docs) {
                            docsSaved += docs.ops.length
                            callback();
                    });
            }else {
                    callback()
            }
    }, function (err) {
            console.log (" gameResult.js > BULK INSERT AMOUNT: ", arrOfResults.length, "docsSaved  " , docsSaved, " DIFF TIME:",Date.now() - startTime);
    });
}

1
ด้วยการระบุคุณสมบัติ .collection คุณกำลังข้ามพังพอน (การตรวจสอบความถูกต้องวิธีการ 'ก่อน' ... )
Derek

0

การแบ่งปันรหัสการทำงานและที่เกี่ยวข้องจากโครงการของเรา:

//documentsArray is the list of sampleCollection objects
sampleCollection.insertMany(documentsArray)  
    .then((res) => {
        console.log("insert sampleCollection result ", res);
    })
    .catch(err => {
        console.log("bulk insert sampleCollection error ", err);
    });

คำ.insertManyตอบได้รับแล้ว (และอธิบาย) ในคำตอบปี 2559นี้
Dan Dascalescu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.