Nodejs中如何对用mongoose对内嵌文档进行类似upsert的操作呢?

Nodejs中如何对用mongoose对内嵌文档进行类似upsert的操作呢?

Schema = {
uid:{type:ObjectId},
reply:[]
}

我想在reply里push每一个人的对话集合

reply:[
  {
    user_id:123,
    commnet:[]
  },
  {
    user_id:456,
    comment:[]
  }
]

如果我想在user_id:789的comment里面push一条对话内容

{
  user_id:789,
  comment:[
    {
     //内容
    }
  ]
}

得先判断user_id:789的对话集合是否存在,如果不存在,创建它

find()该文档后用遍历可以实现,但是太耗时

var exists = false;
var index;
for(var i in reply){//reply为find()后返回的doc.reply
  if(reply[i].user_id == '789'){
    exists = true;
    index = i;
    return;
  }
}
if(exists){//如果存在
  reply[i].comment.push({//内容})
}else{//如果不存在
  reply.push({
    user_id:789,
    comment:[
      {
       //内容
      }
    ]
  })
}

很明显,这样做太耗时,而且繁杂,有没有更简便的方法实现上面的东西呢?


6 回复

要在Node.js中使用Mongoose对内嵌文档进行类似upsert的操作,可以通过使用findOneAndUpdate方法来简化流程。这种方法可以在查询到文档后自动插入或更新指定的内嵌文档,从而避免了手动遍历和判断的过程。

假设我们有一个Schema定义如下:

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

const replySchema = new Schema({
  user_id: { type: Number, required: true },
  comment: [{ content: String }]
});

const mainSchema = new Schema({
  uid: { type: mongoose.Schema.Types.ObjectId },
  reply: [replySchema]
});

const MainModel = mongoose.model('Main', mainSchema);

现在我们需要在reply数组中添加一个新用户(例如user_id: 789)的评论。我们可以使用findOneAndUpdate方法来实现这个操作:

async function addCommentToUser(uid, user_id, commentContent) {
  const filter = { uid: uid };
  const update = {
    $push: {
      reply: {
        $each: [
          {
            user_id: user_id,
            comment: [{ content: commentContent }]
          }
        ],
        $position: 0 // 可以选择插入的位置
      }
    }
  };

  const options = {
    upsert: true, // 如果没有找到匹配的文档,则创建一个新的
    new: true,    // 返回更新后的文档
    runValidators: true // 运行验证器
  };

  try {
    const result = await MainModel.findOneAndUpdate(filter, update, options);
    console.log(result); // 输出更新后的文档
  } catch (error) {
    console.error(error);
  }
}

// 使用示例
addCommentToUser('some-uid', 789, 'Hello World!');

在这个例子中,$push 操作符用于向 reply 数组中添加新的文档。$each$position 用于指定要插入的具体位置。upsert 设置为 true 表示如果没有找到匹配的文档,则会创建一个新的。

这样,我们就能够高效地完成对内嵌文档的upsert操作,而不需要手动遍历和检查是否存在。


http://cnodejs.org/topic/50a60955637ffa4155faf861 我本来一直都是像我那样遍历的,我昨天晚上看你的帖子,看到省时多了,立马就想把自己的前面写的都改了,但是一直没弄好,aggregate只能获取数据,不能对数据进行操作保存啊

求指点呐

眼看小弟的网站就要上线了,这点问题还没解决,求大神们指导啊

要在Mongoose中对内嵌文档执行类似upsert的操作,你可以使用findOneAndUpdate方法,并结合$push$elemMatch操作符。这样可以避免显式的查找和更新过程,从而提高效率。

以下是一个示例代码,展示了如何实现上述需求:

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

const ReplySchema = new Schema({
  user_id: { type: String, required: true },
  comment: [{ text: String }]  // 假设comment是一个对象数组,每个对象有一个text字段
});

const MessageSchema = new Schema({
  uid: { type: Schema.Types.ObjectId },
  reply: [ReplySchema]
});

const Message = mongoose.model('Message', MessageSchema);

async function updateReply(uid, user_id, comment) {
  const filter = {
    uid,
    reply: { $elemMatch: { user_id } }
  };

  const update = {
    $push: {
      'reply.$.comment': comment
    }
  };

  const options = {
    upsert: true,
    new: true
  };

  try {
    const result = await Message.findOneAndUpdate(filter, update, options);
    console.log(result);
  } catch (error) {
    console.error(error);
  }
}

updateReply('some-uid', '789', { text: 'Hello World' });

在这个示例中:

  1. filter用于定位包含指定user_idreply
  2. update使用$push操作符来向匹配的reply中的comment数组添加新的评论。
  3. options设置upsert: true表示如果找不到匹配的文档,则插入一个新的文档。new: true确保返回更新后的文档,而不是原始文档。

这种方法比手动遍历和查找更高效且简洁。

回到顶部