通过猫鼬将项目推入mongo数组


185

我一直在寻找答案,但我确定我迷失了正确的词来描述我的追求。

基本上,我有一个名为“ people”的mongodb集合,该集合的架构如下:

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

现在,我有一个非常基本的express应用程序,该应用程序连接到数据库并使用空的Friends数组成功创建了“ people”。

在应用程序的次要位置,有一个添加好友的表单。该表单采用firstName和lastName,然后使用带有名称字段的POST来引用适当的people对象。

我很难做的是创建一个新的朋友对象,然后将其“推送”到friends数组中。

我知道,当我通过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}});
};

我看到我可以潜在地使用collections.findOneAndUpdate(),但是我不确定该在哪里实现?在我的模型中?
Neurax

Answers:


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
我以为并发写保护方面的第二种选择实际上是更安全的选择?当您想说前者时,您是否不小心说了后者?
Will Brickner '17

37
是的,我只是检查和(11月2017),IS安全使用猫鼬update的功能,同时IS NOT安全查找文件,修改它在内存中,然后调用.save()该文件的方法。当我说某项操作是“安全的”时,它意味着即使对文档应用了一次,两次或50次更改,所有更改都会被成功应用,并且更新的行为将与您期望的一样。本质上,内存中操作是不安全的,因为您可能正在处理过时的文档,因此在保存时,将丢失在获取步骤之后发生的更改。
Will Brickner '17

2
@Will Brickner的一个常见工作流程是将您的逻辑包装在重试循环中:(可重试包含获取,修改,保存)。如果返回VersionError(乐观锁异常),则可以多次重试该操作,并每次获取一个新副本。不过,我仍然尽可能地选择原子更新!
阿德里安·施耐德

8
@ZackOfAllTrades也让我感到困惑,但是我相信完成是回调函数。let done = function(err, result) { // this runs after the mongoose operation }
用户

如何在回调中获取好友对象的ID?
Dee Nix

41

$推操作者附加一个指定值的数组。

{ $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 Toast,

请允许我指出您的代码中可能有一些错误。之所以可以使用它,是因为我为项目输入了正确的变量。您在哪里拥有Friend.findOneAndUpdate(),我认为应该是People.findOneAndUpdate()。那会更符合原始问题。我可以为您编辑它,但是我希望您仔细检查一下以防万一(我对node / express有点陌生)。
Cheesus Toast,

@CheesusToast我认为,如果我错了,可以更改答案。我把这个答案对我来说很好。但是,如果您发现此答案有误,则可以更改此答案,如果您纠正我的先生,我会很高兴的:-)。
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
}

2

一种简单的方法是使用以下内容:

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

0

就我而言,我这样做了

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

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

降低投票率的原因可能是因为这似乎没有必要。拉瓦尔(Parth Raval)的答案就足够了。
Cheesus Toast,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.