通过mongoose将项目推送到mongo数组

Neu*_*rax 133 mongoose mongodb node.js express

我一直在寻找答案,但我确信我已经迷失了正确的词语来形容我所追求的目标.

基本上我有一个名为'people'的mongodb集合该集合的模式如下:

people: {
         name: String, 
         friends: [{firstName: String, lastName: String}]
        }
Run Code Online (Sandbox Code Playgroud)

现在,我有一个非常基本的快速应用程序连接到数据库并成功创建一个空朋友数组的'人'.

在应用程序的辅助位置,有一个表单来添加朋友.表单接受firstName和lastName,然后使用名称字段POST,以便引用正确的人员对象.

我正在做的事情是创建一个新的朋友对象,然后将其"推送"到friends数组中.

我知道当我通过mongo控制台执行此操作时,我使用更新函数,在查找条件之后使用$ push作为我的第二个参数,但我似乎无法找到让mongoose执行此操作的适当方法.

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

更新: 所以,阿德里安的回答非常有帮助.以下是我为实现目标所做的工作.

在我的app.js文件中,我使用了一个临时路由

app.get('/addfriend', users.addFriend);
Run Code Online (Sandbox Code Playgroud)

在我的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}});
};
Run Code Online (Sandbox Code Playgroud)

Adr*_*der 206

假设, var friend = { firstName: 'Harry', lastName: 'Potter' };

您有两种选择:

在内存中更新模型,并保存(plain javascript array.push):

person.friends.push(friend);
person.save(done);
Run Code Online (Sandbox Code Playgroud)

要么

PersonModel.update(
    { _id: person._id }, 
    { $push: { friends: friend } },
    done
);
Run Code Online (Sandbox Code Playgroud)

我总是尽可能地尝试第一种选择,因为它会更多地尊重猫鼬给你带来的好处(钩子,验证等).

但是,如果您正在进行大量并发写入操作,那么您将遇到竞争条件,您最终会遇到令人讨厌的版本错误,以阻止您每次更换整个模型并丢失您添加的上一个朋友.因此,只有在绝对必要时才会选择后者.

  • 是的,我刚检查过(2017年11月),**它_IS_安全**使用mongoose`update`函数,而**它_IS NOT_ safe**找到一个文件,在内存中修改它,然后调用文档上的`.save()`方法.当我说操作是"安全的"时,这意味着即使对文档应用了一个,两个或50个更改,它们也将成功应用,并且更新的行为将如您所期望的那样.基本上内存操作是不安全的,因为您可能正在处理过时的文档,因此在保存时,在获取步骤之后发生的更改将丢失. (21认同)
  • @ZackOfAllTrades也让我感到困惑,但我相信完成是回调函数。`let done = function(err,result){//这在猫鼬操作之后运行}` (4认同)
  • 我认为就并发写保护而言,第二个选项实际上更安全?当你想说前者时,你是否不小心说后者了? (2认同)
  • @Will Brickner一个常见的工作流程就是将你的逻辑包装在一个重试循环中:( retryable包含fetch,modify,save).如果您返回VersionError(乐观锁定异常),则可以重复尝试该操作几次并每次获取一个新副本.尽管如此,我仍然更喜欢原子更新! (2认同)

Par*_*val 28

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

{ $push: { <field1>: <value1>, ... } }
Run Code Online (Sandbox Code Playgroud)

$ 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);
        }
    });
)
Run Code Online (Sandbox Code Playgroud)

  • 这是我发现有效的答案,所以我认为这是截至 2019 年最新的答案。我认为最好的答案在某种程度上有所缺乏,而且可能不完整/过时。 (2认同)
  • 好的,没问题,无论如何这只是一个小的编辑。这对我来说有点挑剔,因为观众(像我一样)无论如何都会弄清楚阵列被推到哪里。我仍然认为这应该是最好的答案:) (2认同)
  • 只是想让其他人知道这工作得很好,现在已经是 2020 年了,而且仍然工作得很好。我只是使用 findById 而不是 findByOne,无论如何,感谢您的帮助。 (2认同)

Ava*_*iya 11

使用 Mongoose 将项目推入数组的另一种方法是 - $addToSet,如果您只想将唯一项目推入数组。$push运算符只是将对象添加到数组中,无论对象是否已经存在,而$addToSet仅在对象不存在于数组中时才会这样做,以免合并重复。

PersonModel.update(
  { _id: person._id }, 
  { $addToSet: { friends: friend } }
);
Run Code Online (Sandbox Code Playgroud)

这将查找您要添加到数组的对象。如果找到,则不执行任何操作。如果没有,则将其添加到数组中。

参考:


Rax*_*axy 6

首先我尝试了这段代码

const peopleSchema = new mongoose.Schema({
  name: String,
  friends: [
    {
      firstName: String,
      lastName: String,
    },
  ],
});
const People = mongoose.model("person", peopleSchema);
const first = new Note({
  name: "Yash Salvi",
  notes: [
    {
      firstName: "Johnny",
      lastName: "Johnson",
    },
  ],
});
first.save();
const friendNew = {
  firstName: "Alice",
  lastName: "Parker",
};
People.findOneAndUpdate(
  { name: "Yash Salvi" },
  { $push: { friends: friendNew } },
  function (error, success) {
    if (error) {
      console.log(error);
    } else {
      console.log(success);
    }
  }
);
Run Code Online (Sandbox Code Playgroud)

但我注意到只有第一个朋友(即约翰·约翰逊)被保存,并且在现有的“朋友”数组中推送数组元素的目标似乎不起作用,因为当我运行代码时,数据库中只显示“第一个朋友”而“朋友”数组只有一个元素!所以简单的解决方案写在下面

const peopleSchema = new mongoose.Schema({
  name: String,
  friends: [
    {
      firstName: String,
      lastName: String,
    },
  ],
});
const People = mongoose.model("person", peopleSchema);
const first = new Note({
  name: "Yash Salvi",
  notes: [
    {
      firstName: "Johnny",
      lastName: "Johnson",
    },
  ],
});
first.save();
const friendNew = {
  firstName: "Alice",
  lastName: "Parker",
};
People.findOneAndUpdate(
  { name: "Yash Salvi" },
  { $push: { friends: friendNew } },
  { upsert: true }
);
Run Code Online (Sandbox Code Playgroud)

在我的案例中添加“{ upsert:true}”解决了问题,一旦保存代码并运行它,我就会看到“friends”数组现在有2个元素! 如果对象不存在, upsert = true 选项会创建该对象。默认设置为false。

如果它不起作用,请使用以下代码段

People.findOneAndUpdate(
  { name: "Yash Salvi" },
  { $push: { friends: friendNew } },
).exec();
Run Code Online (Sandbox Code Playgroud)


KAR*_*N.A 5

使用$push以更新文档和插入内部数组新的价值。

找:

db.getCollection('noti').find({})
Run Code Online (Sandbox Code Playgroud)

查找结果:

{
    "_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
}
Run Code Online (Sandbox Code Playgroud)

更新:

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

更新结果:

{
    "_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
}
Run Code Online (Sandbox Code Playgroud)


小智 5

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

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

  • 容易出现竞争条件(如果您并行实例化多个 John,您将丢失推送的值之一)。 (2认同)