Đẩy các mục vào mảng mongo thông qua mongoose


183

Tôi đã lùng sục một chút để tìm kiếm câu trả lời nhưng tôi chắc chắn rằng tôi đã mất những từ thích hợp để mô tả những gì tôi đang theo dõi.

Về cơ bản tôi có một bộ sưu tập mongodb được gọi là 'people' Lược đồ cho bộ sưu tập đó như sau:

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

Bây giờ, tôi có một ứng dụng thể hiện rất cơ bản kết nối với cơ sở dữ liệu và tạo thành công 'người' với một mảng bạn bè trống.

Ở vị trí thứ cấp trong ứng dụng, một biểu mẫu được đặt ra để thêm bạn bè. Biểu mẫu lấy trong FirstName và LastName và sau đó POST với trường tên cũng để tham chiếu đến đối tượng người thích hợp.

Điều tôi đang gặp khó khăn là tạo một đối tượng bạn bè mới và sau đó "đẩy" nó vào mảng bạn bè.

Tôi biết rằng khi tôi thực hiện việc này thông qua bảng điều khiển mongo, tôi sử dụng chức năng cập nhật với $ push làm đối số thứ hai của mình sau tiêu chí tra cứu, nhưng dường như tôi không thể tìm ra cách thích hợp để mongoose làm điều này.

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

CẬP NHẬT: Vì vậy, câu trả lời của Adrian rất hữu ích. Sau đây là những gì tôi đã làm để thực hiện mục tiêu của mình.

trong tệp app.js của mình, tôi đặt tuyến đường tạm thời bằng cách sử dụng

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

nơi tôi có tập tin 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}});
};

Tôi thấy rằng tôi có khả năng có thể sử dụng các bộ sưu tập.findOneAndUpdate (), nhưng tôi không chắc chắn nơi tôi sẽ thực hiện điều đó? Trong mô hình của tôi?
Neurax

Câu trả lời:


281

Giả định, var friend = { firstName: 'Harry', lastName: 'Potter' };

Có hai lựa chọn bạn có:

Cập nhật mô hình trong bộ nhớ và lưu (javascript Array.push):

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

hoặc là

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

Tôi luôn cố gắng và lựa chọn đầu tiên khi có thể, bởi vì nó sẽ tôn trọng nhiều hơn những lợi ích mà cầy mangut mang lại cho bạn (móc, xác nhận, v.v.).

Tuy nhiên, nếu bạn đang thực hiện nhiều thao tác viết đồng thời, bạn sẽ gặp các điều kiện cuộc đua trong đó bạn sẽ gặp phải các lỗi phiên bản khó chịu để ngăn bạn thay thế toàn bộ mô hình mỗi lần và mất người bạn trước đó bạn đã thêm. Vì vậy, chỉ đi đến cái trước khi nó thực sự cần thiết.


1
Tôi nghĩ rằng tùy chọn thứ hai thực sự là lựa chọn an toàn hơn về mặt bảo vệ ghi đồng thời? Bạn đã vô tình nói sau khi bạn có ý định nói trước?
Will Brickner

37
Yep, tôi chỉ kiểm tra và (trong tháng 11 năm 2017), an toàn để sử dụng mongoose updatechức năng, trong khi KHÔNG PHẢI LÀ an toàn để tìm một tài liệu, sửa đổi nó trong bộ nhớ, và sau đó gọi các .save()phương pháp trên tài liệu. Khi tôi nói rằng một thao tác là 'an toàn', điều đó có nghĩa là ngay cả khi một, hai hoặc 50 thay đổi đang được áp dụng cho một tài liệu, tất cả chúng sẽ được áp dụng thành công và hành vi của các cập nhật sẽ như bạn mong đợi. Về cơ bản, thao tác trong bộ nhớ là không an toàn vì bạn có thể đang làm việc trên một tài liệu lỗi thời nên khi bạn lưu, những thay đổi xảy ra sau bước tìm nạp sẽ bị mất.
Will Brickner

2
@Will Brickner một quy trình công việc phổ biến cho việc đó là bọc logic của bạn trong một vòng lặp thử lại: (retryable chứa tìm nạp, sửa đổi, lưu). Nếu bạn lấy lại VersionError (ngoại lệ khóa lạc quan), bạn có thể thử lại thao tác đó một vài lần và tìm nạp một bản sao mới mỗi lần. Tôi vẫn thích cập nhật nguyên tử khi có thể, mặc dù!
Adrian Schneider

8
@ZackOf ALLTrades Tôi cũng bối rối, nhưng tôi tin rằng thực hiện là chức năng gọi lại. let done = function(err, result) { // this runs after the mongoose operation }
người dùng

Làm thế nào để có được id của đối tượng bạn bè trong cuộc gọi lại?
Dee Nix

41

Các $ đẩy khai thác gắn thêm một giá trị nhất định để một mảng.

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

$ đẩy thêm trường mảng với giá trị là phần tử của nó.

Câu trả lời trên đáp ứng tất cả các yêu cầu, nhưng tôi đã làm cho nó hoạt động bằng cách làm như sau

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);
        }
    });
)

Đây là một trong những gì tôi đã tìm thấy để làm việc, vì vậy tôi nghĩ rằng đây là một trong những cập nhật nhất vào năm 2019. Câu trả lời tốt nhất tôi nghĩ là thiếu một cách nào đó và có thể không đầy đủ / lỗi thời.
Bánh mì nướng phô mai

Tôi có thể chỉ ra rằng bạn có thể có một lỗi nhỏ trong mã. Tôi đã làm cho nó hoạt động vì tôi đặt biến chính xác cho dự án của tôi. Nơi bạn có Friend.findOneAndUpdate () Tôi nghĩ đó phải là People.findOneAndUpdate (). Điều đó sẽ phù hợp hơn với câu hỏi ban đầu. Tôi có thể chỉnh sửa nó cho bạn nhưng tôi muốn bạn kiểm tra lại trong trường hợp tôi sai (tôi hơi mới với nút / express).
Bánh mì nướng phô mai

@CheesusToast Tôi nghĩ, nếu tôi sai, bạn có thể thay đổi câu trả lời. tôi đã đưa ra câu trả lời này đã làm việc tốt cho tôi. nhưng nếu bạn thấy câu trả lời này sai, bạn có thể thay đổi câu trả lời này và tôi sẽ rất vui nếu bạn sửa cho tôi thưa ông :-).
Parth Raval

1
OK, không vấn đề gì, dù sao nó cũng chỉ là một chỉnh sửa nhỏ. Đó là loại kén chọn của tôi bởi vì những người xem (như tôi) sẽ tìm ra nơi mà mảng được đẩy đến bằng mọi cách. Tôi vẫn nghĩ đây là câu trả lời hay nhất :)
Cheesus Toast

9

Sử dụng $pushđể cập nhật tài liệu và chèn giá trị mới bên trong một mảng.

tìm thấy:

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

kết quả tìm kiếm:

{
    "_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
}

cập nhật:

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

kết quả để cập nhật:

{
    "_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
}

2

Một cách dễ dàng để làm điều đó là sử dụng như sau:

var John = people.findOne({name: "John"});
John.friends.push({firstName: "Harry", lastName: "Potter"});
John.save();

0

Trong trường hợp của tôi, tôi đã làm điều này

  const eventId = event.id;
  User.findByIdAndUpdate(id, { $push: { createdEvents: eventId } }).exec();

-3

Tôi cũng gặp phải vấn đề này. Cách khắc phục của tôi là tạo một lược đồ con. Xem dưới đây cho một ví dụ cho các mô hình của bạn.

---- Người mẫu

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);

*** Quan trọng: SingleFriend.schema -> đảm bảo sử dụng chữ thường cho lược đồ

--- Lược đồ con

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

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

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

Có thể lý do cho downvote là vì điều này dường như không cần thiết. Câu trả lời của Parth Raval là khá đầy đủ.
Bánh mì nướng phô mai
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.