Висувайте елементи в масив mongo через мангуст


185

Я добре проглянув ТАК, шукаючи відповіді, але впевнений, що втрачаю правильні слова, щоб описати те, що я шукаю.

В основному у мене є колекція mongodb під назвою "people" Схема для цієї колекції така:

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

Тепер у мене дуже базовий експрес-додаток, який підключається до бази даних і успішно створює "людей" з порожнім масивом друзів.

На другому місці в додатку є форма для додавання друзів. Форма бере у firstName та lastName, а потім POST з полем імені також для посилань на належні люди.

Те, що мені важко робити, - це створити новий об’єкт друга, а потім "просунути" його в масив друзів.

Я знаю, що коли я роблю це через консоль 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}});
};

Я бачу, що я міг би потенційно використовувати collection.findOneAndUpdate (), але я не впевнений, де б це застосувати? У моїй моделі?
Неуракс

Відповіді:


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

Я завжди намагаюся йти за першим варіантом, коли це можливо, оскільки це буде поважати більше переваг, які дає мангуст (гачки, перевірка тощо).

Однак, якщо ви робите багато одночасних записів, ви потрапите на умови гонки, коли у вас виникнуть неприємні помилки версії, які не дозволять вам замінювати всю модель щоразу і втрачаєте попереднього друга, якого ви додали. Тож переходьте до колишнього лише тоді, коли це абсолютно необхідно.


1
Я думав, що другий варіант насправді є більш безпечним з точки зору паралельного захисту від запису? Ви випадково сказали останнє, коли мали намір сказати колишнє?
Буде Брікнер

37
Так, я тільки що перевірив і (в листопаді 2017 року), це IS безпечно використовувати мангуст updateфункцію, в той час як це НЕ безпечно знайти документ, змінити його в пам'яті, а потім викликати .save()метод на документі. Коли я кажу, що операція є "безпечною", це означає, що навіть якщо до документа будуть застосовані одна, дві або 50 змін, всі вони будуть успішно застосовані і поведінка оновлень буде такою, як ви очікуєте. По суті, маніпуляція в пам'яті небезпечна, тому що ви можете працювати над застарілим документом, тому при збереженні зміни, які відбулися після кроку отримання, втрачаються.
Буде Брікнер

2
@ Буде Brickner загальним робочим процесом, який полягає в тому, щоб обернути свою логіку в циклі повторного повтору: (повторний файл містить видобуток, зміну, збереження). Якщо ви повернете VersionError (виняток з оптимістичного блокування), ви можете повторити спробу цієї операції кілька разів і кожен раз отримувати нову копію. Я все ще віддаю перевагу атомним оновленням, коли це можливо!
Адріан Шнайдер

8
@ZackOfAllTrades Мене теж бентежить, але я вважаю, що це функція зворотного дзвінка. let done = function(err, result) { // this runs after the mongoose operation }
користувач

як отримати ідентифікатор об’єкта друга в зворотному дзвінку?
Ді Нікс

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

Це той, над яким я виявив роботу, тому я вважаю, що це найбільше актуально станом на 2019 рік. Найкращий варіант відповіді, на мою думку, не вистачає і, можливо, є неповним / застарілим.
Чіз-тост

Чи можу я лише зазначити, що у вас може виникнути невелика помилка в коді. Я змусив його працювати, тому що ставлю правильну змінну для свого проекту. Там, де у вас є Friend.findOneAndUpdate (), я думаю, це має бути People.findOneAndUpdate (). Це більше відповідало б оригінальному питанню. Я міг би відредагувати це для вас, але я б краще, щоб ви просто двічі перевірили це, якщо я помиляюся (я трохи новий для вузла / вираження).
Чіз-тост

@CheesusToast Я думаю, якщо я помиляюся, ви можете змінити відповідь. я поставив цю відповідь, яка добре працювала для мене. але якщо ви знайдете цю відповідь неправильною, ви можете змінити цю відповідь, і я буду радий, якщо ви виправте мене :-).
Parth Raval

1
Гаразд, немає проблем, все одно це було лише невелике редагування. Мені це начебто вибаглива нітка, тому що глядачі (як я) спрацювали б там, де масив був би підштовхнутий. Я все ще думаю, що це має бути найкращою відповіддю :)
Сир тост

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
}

2

Простий спосіб зробити це - скористатися наступним:

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


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

Можливо, причиною знищення є те, що це не здається необхідним. Відповідь Парта Раваля цілком достатня.
Чіст-тост
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.