我正在构建一个应用程序,我需要在聊天室中将消息添加为子文档。我需要在将其插入现有房间后立即返回子文档的数据。这是我的代码
Room.findOne({ roomname: data.room }, (err, room) => {
room.messages.push({ username: data.username, message: data.message });
room.save((err, room) => {
socket.broadcast.to(data.room).emit("new message", {
username: room.messages.slice(-1).name,
message: room.messages.slice(-1).message,
createdat: room.messages.slice(-1).createdat
});
});
});
所以这是我用来检索最后一个子文档的代码。还有其他方法可以达到这个目的吗?
答案 0 :(得分:1)
room.messages.slice(-1).name
这是不正确的,下面的演示
[1,2,3].slice(-1)
// returns [3], not 3
您仍然需要使用索引
room.messages.slice(-1)[0].name
// or simply
room.messages[room.messages.length - 1].name
答案 1 :(得分:1)
使用.findOneAndUpdate()
代替$push
。这样你只需“触摸一次”数据库,它也避免了其他东西可能修改文件而你最终覆盖它的问题。这样可以避免.find()
然后.save()
模式的危险:
Room.findOneAndUpdate(
{ roomname: data.room },
{ "$push": {
"messages": { username: data.username, message: data.message }
}},
{ "new": true },
(err, room) => {
let message = room.messages.slice(-1)[0];
socket.broadcast.to(data.room).emit(
"new message",
Object.keys(message).filter(k => k !== "_id")
.reduce((acc,curr) => Object.assign(acc,{ [curr]: message[curr] }),{})
);
}
);
另外,只需.slice(-1)[0]
获取整个对象并返回它,或者如上所示过滤掉不需要的密钥。
或者甚至只是简单地返回数组元素中的所有字段,并从数组$slice
返回来自服务器的查询:
Room.findOneAndUpdate(
{ roomname: data.room },
{ "$push": {
"messages": { username: data.username, message: data.message }
}},
{ "new": true, "fields": { "messages": { "$slice": -1 } } },
(err, room) => {
socket.broadcast.to(data.room).emit(
"new message", room.messages[0]
);
}
);