Вставьте предметы в массив монго через мангуста


185

Я так хорошо искал ответ в поисках ответа, но уверен, что потерян для правильных слов, чтобы описать, что мне нужно.

По сути, у меня есть коллекция mongodb под названием «people». Схема для этой коллекции следующая:

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

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

На втором месте в приложении находится форма для добавления друзей. Форма принимает firstName и lastName, а затем POST с полем имени также для ссылки на соответствующий объект people.

Что мне тяжело делать, так это создать новый объект друзей и затем «протолкнуть» его в массив друзей.

Я знаю, что когда я делаю это через консоль Монго, я использую функцию обновления с $ 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 (), но я не уверен, где бы я это реализовал? В моей модели?
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
);

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

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


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

37
Да, я только что проверил и (в ноябре 2017 года), это IS безопасно использовать мангуст updateфункцию, в то время как это НЕ безопасно найти документ, изменить его в памяти, а затем вызвать .save()метод на документе. Когда я говорю, что операция «безопасна», это означает, что даже если к документу применяются одно, два или 50 изменений, все они будут успешно применены, и поведение обновлений будет таким, как вы ожидаете. По сути, манипулирование в памяти небезопасно, поскольку вы можете работать с устаревшим документом, поэтому при сохранении изменения, произошедшие после шага выборки, теряются.
Уилл Брикнер

2
@Will Brickner - это обычный рабочий процесс, заключающийся в том, чтобы заключить логику в цикл повторов: (retryable содержит выборку, изменение, сохранение). Если вы получите ошибку VersionError (исключение для оптимистической блокировки), вы можете повторить эту операцию несколько раз и каждый раз получать новую копию. Я все еще предпочитаю атомарные обновления, когда это возможно!
Адриан Шнайдер

8
@ZackOfAllTrades меня тоже смутило, но я верю, что функция callback выполнена 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 год. Тот, который является лучшим ответом, я думаю, не хватает каким-то образом и, возможно, неполным / устаревшим.
Тост Cheesus

Позвольте мне отметить, что у вас может быть небольшая ошибка в коде. Я заставил это работать, потому что я поместил правильную переменную для моего проекта. Где у вас есть Friend.findOneAndUpdate () Я думаю, что это должен быть People.findOneAndUpdate (). Это будет больше соответствовать первоначальному вопросу. Я мог бы отредактировать его для вас, но я бы предпочел, чтобы вы дважды проверили его на случай, если я ошибаюсь (я немного новичок в узле / экспрессе).
Тост Cheesus

@ ChessusToast Я думаю, если я ошибаюсь, вы можете изменить ответ. Я поставил этот ответ, который работал хорошо для меня. но если вы найдете этот ответ неправильным, вы можете изменить этот ответ, и я буду рад, если вы поправите меня, сэр :-).
Парт Равал

1
ОК, нет проблем, это было всего лишь небольшое редактирование. Это отчасти придирчиво ко мне, потому что зрители (как и я) должны были бы решить, куда в любом случае толкнуть массив. Я все еще думаю, что это должен быть лучший ответ :)
Тост Cheesus

10

Используйте $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);

Возможно, причина понижения в том, что это не кажется необходимым. Ответ Парта Равала вполне достаточен.
Тост Cheesus
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.