ผลักรายการลงในอาร์เรย์ mongo ผ่าน mongoose


185

ฉันค้นหาคำตอบแล้ว แต่ฉันแน่ใจว่าฉันหายไปเพราะคำพูดที่ถูกต้องเพื่ออธิบายสิ่งที่ฉันตามมา

โดยทั่วไปฉันมีคอลเลกชัน MongoDB ที่เรียกว่า 'people' schema สำหรับการรวบรวมนั้นมีดังนี้:

people: {
         name: String, 
         friends: [{firstName: String, lastName: String}]
        }

ตอนนี้ฉันมีแอปพลิเคชันด่วนขั้นพื้นฐานที่เชื่อมต่อกับฐานข้อมูลและสร้าง 'คน' ด้วยอาร์เรย์เพื่อนที่ว่างเปล่าได้สำเร็จ

ในตำแหน่งรองในแอปพลิเคชันจะมีแบบฟอร์มเพื่อเพิ่มเพื่อน แบบฟอร์มที่ใช้ในชื่อและนามสกุลจากนั้นโพสต์พร้อมกับฟิลด์ชื่อยังสำหรับการอ้างอิงถึงวัตถุคนที่เหมาะสม

สิ่งที่ฉันกำลังลำบากในการทำคือการสร้างวัตถุเพื่อนใหม่แล้ว "ผลัก" วัตถุนั้นลงในอาร์เรย์เพื่อน

ฉันรู้ว่าเมื่อฉันทำสิ่งนี้ผ่านทางคอนโซล mongo ฉันใช้ฟังก์ชั่นอัพเดทด้วย $ push เป็นอาร์กิวเมนต์ที่สองของฉันหลังจากเกณฑ์การค้นหา แต่ฉันไม่สามารถหาวิธีที่เหมาะสมเพื่อให้พังพอนทำเช่นนี้

db.people.update({name: "John"}, {$push: {friends: {firstName: "Harry", lastName: "Potter"}}});

ปรับปรุง: ดังนั้นคำตอบของเอเดรียเป็นประโยชน์มาก ต่อไปนี้เป็นสิ่งที่ฉันทำเพื่อบรรลุเป้าหมาย

ในไฟล์ app.js ของฉันฉันกำหนดเส้นทางชั่วคราวโดยใช้

app.get('/addfriend', users.addFriend);

ฉันอยู่ที่ไหนในไฟล์ users.js ของฉัน

exports.addFriend = function (req, res, next)
{
var friend = {"firstName": req.body.fName, "lastName": req.body.lName};
Users.findOneAndUpdate({name: req.user.name}, {$push: {friends: friend}});
};

ฉันเห็นว่าฉันอาจจะใช้คอลเล็กชันได้ FindOneAndUpdate () แต่ฉันไม่แน่ใจว่าจะใช้งานที่ไหน ในรูปแบบของฉัน?
Neurax

คำตอบ:


282

สมมติ var friend = { firstName: 'Harry', lastName: 'Potter' };

คุณมีสองตัวเลือก:

อัปเดตโมเดลในหน่วยความจำและบันทึก (javascript array.push ธรรมดา):

person.friends.push(friend);
person.save(done);

หรือ

PersonModel.update(
    { _id: person._id }, 
    { $push: { friends: friend } },
    done
);

ฉันมักจะลองและไปหาตัวเลือกแรกเมื่อเป็นไปได้เพราะมันจะเคารพผลประโยชน์มากมายที่พังพอนให้คุณ (hooks, validation, etc. )

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


1
ฉันคิดว่าตัวเลือกที่สองเป็นจริงปลอดภัยกว่าในแง่ของการป้องกันการเขียนพร้อมกันหรือไม่ คุณตั้งใจจะพูดทีหลังเมื่อคุณตั้งใจจะพูดอดีตหรือไม่?
Will Brickner

37
อ๋อฉันเพียงแค่ตรวจสอบและ (ในพฤศจิกายน 2017) มันเป็นความปลอดภัยที่จะใช้พังพอนupdateฟังก์ชั่นในขณะที่มันไม่ได้มีความปลอดภัยในการค้นหาเอกสารแก้ไขในหน่วยความจำแล้วเรียก.save()วิธีการในเอกสาร เมื่อฉันพูดว่าการดำเนินการนั้น 'ปลอดภัย' หมายความว่าแม้ว่าจะมีการใช้การเปลี่ยนแปลงหนึ่งสองหรือ 50 รายการในเอกสารการดำเนินการทั้งหมดจะถูกนำไปใช้อย่างประสบความสำเร็จและพฤติกรรมของการอัปเดตจะเป็นไปตามที่คุณคาดหวัง การจัดการในหน่วยความจำโดยพื้นฐานนั้นไม่ปลอดภัยเนื่องจากคุณสามารถทำงานกับเอกสารที่ล้าสมัยดังนั้นเมื่อคุณบันทึกการเปลี่ยนแปลงที่เกิดขึ้นหลังจากขั้นตอนการดึงข้อมูลสูญหาย
Will Brickner

2
@Will Brickner จะมีเวิร์กโฟลว์ทั่วไปสำหรับการห่อตรรกะของคุณในการลองส่งซ้ำ: (สามารถลองใหม่ได้มีการดึงข้อมูลแก้ไขบันทึก) หากคุณได้รับ VersionError กลับมา (ข้อยกเว้นการล็อคในแง่ดี) คุณสามารถลองการดำเนินการอีกครั้งสองสามครั้งและดึงสำเนาใหม่ในแต่ละครั้ง ฉันยังคงชอบการอัปเดตของอะตอมเมื่อเป็นไปได้!
Adrian Schneider เมื่อ

8
@ZackOfAllTrades สร้างความสับสนให้ฉันด้วย แต่ฉันเชื่อว่าเสร็จแล้วคือฟังก์ชั่นโทรกลับ let done = function(err, result) { // this runs after the mongoose operation }
ผู้ใช้

วิธีรับ id ของวัตถุเพื่อนในการติดต่อกลับ?
Dee Nix

41

ตัวดำเนินการ$ pushผนวกค่าที่ระบุเข้ากับอาร์เรย์

{ $push: { <field1>: <value1>, ... } }

$ pushเพิ่มเขตข้อมูลอาร์เรย์ที่มีค่าเป็นองค์ประกอบ

คำตอบข้างต้นตอบสนองความต้องการทั้งหมด แต่ฉันได้ทำงานด้วยการทำดังต่อไปนี้

var objFriends = { fname:"fname",lname:"lname",surname:"surname" };
Friend.findOneAndUpdate(
   { _id: req.body.id }, 
   { $push: { friends: objFriends  } },
  function (error, success) {
        if (error) {
            console.log(error);
        } else {
            console.log(success);
        }
    });
)

นี่คือสิ่งที่ฉันได้พบว่าทำงานดังนั้นฉันคิดว่านี่เป็นข้อมูลล่าสุดในปีพ. ศ. 2562 คำตอบที่ดีที่สุดที่ฉันคิดว่าขาดในบางวิธีและอาจไม่สมบูรณ์ / ล้าสมัย
Cheesus Toast

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

@heesus ขนมปังปิ้งฉันคิดว่าถ้าฉันผิดคุณสามารถเปลี่ยนคำตอบ ฉันได้คำตอบนี้ซึ่งทำงานได้ดีสำหรับฉัน แต่ถ้าคุณพบคำตอบนี้ผิดคุณสามารถเปลี่ยนคำตอบนี้และฉันจะดีใจถ้าคุณแก้ไขฉัน :-)
Parth Raval

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

9

ใช้$pushเพื่ออัปเดตเอกสารและแทรกค่าใหม่ภายในอาร์เรย์

หา:

db.getCollection('noti').find({})

ผลการค้นหา:

{
    "_id" : ObjectId("5bc061f05a4c0511a9252e88"),
    "count" : 1.0,
    "color" : "green",
    "icon" : "circle",
    "graph" : [ 
        {
            "date" : ISODate("2018-10-24T08:55:13.331Z"),
            "count" : 2.0
        }
    ],
    "name" : "online visitor",
    "read" : false,
    "date" : ISODate("2018-10-12T08:57:20.853Z"),
    "__v" : 0.0
}

อัปเดต:

db.getCollection('noti').findOneAndUpdate(
   { _id: ObjectId("5bc061f05a4c0511a9252e88") }, 
   { $push: { 
             graph: {
               "date" : ISODate("2018-10-24T08:55:13.331Z"),
               "count" : 3.0
               }  
           } 
   })

ผลการอัพเดต:

{
    "_id" : ObjectId("5bc061f05a4c0511a9252e88"),
    "count" : 1.0,
    "color" : "green",
    "icon" : "circle",
    "graph" : [ 
        {
            "date" : ISODate("2018-10-24T08:55:13.331Z"),
            "count" : 2.0
        }, 
        {
            "date" : ISODate("2018-10-24T08:55:13.331Z"),
            "count" : 3.0
        }
    ],
    "name" : "online visitor",
    "read" : false,
    "date" : ISODate("2018-10-12T08:57:20.853Z"),
    "__v" : 0.0
}



-3

ฉันพบปัญหานี้เช่นกัน การแก้ไขของฉันคือการสร้างสคีมาของเด็ก ดูตัวอย่างด้านล่างสำหรับรุ่นของคุณ

---- รูปแบบบุคคล

const mongoose = require('mongoose');
const SingleFriend = require('./SingleFriend');
const Schema   = mongoose.Schema;

const productSchema = new Schema({
  friends    : [SingleFriend.schema]
});

module.exports = mongoose.model('Person', personSchema);

*** สำคัญ: SingleFriend.schema -> ตรวจสอบให้แน่ใจว่าใช้ตัวพิมพ์เล็กสำหรับสคีมา

--- โครงสร้างเด็ก

const mongoose = require('mongoose');
const Schema   = mongoose.Schema;

const SingleFriendSchema = new Schema({
  Name: String
});

module.exports = mongoose.model('SingleFriend', SingleFriendSchema);

อาจเป็นสาเหตุของ downvote เพราะมันไม่จำเป็น คำตอบของ Parth Raval นั้นเพียงพอแล้ว
Cheesus Toast
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.