假设我有一系列文件,每个文件都在管理老师和学生之间的讨论:
{
_id,
teacherId,
studentId,
teacherLastMessage,
studentLastMessage
}
我将通过3个参数获得查询:_id
,userId
和message
。
我正在寻找一种方法来更新teacherLastMessage
字段或studentLastMessage
字段,具体取决于用户所在的字段。
目前,我有这个:
return Promise.all([
// if user is teacher, set teacherLastMessage
db.collection('discussions').findOneAndUpdate({
teacherId: userId,
_id
}, {
$set: {
teacherLastMessage: message
}
}, {
returnOriginal: false
}),
// if user is student, set studentLastMessage
db.collection('discussions').findOneAndUpdate({
studentId: userId,
_id
}, {
$set: {
studentLastMessage: message
}
}, {
returnOriginal: false
})
]).then((results) => {
results = results.filter((result) => result.value);
if (!results.length) {
throw new Error('No matching document');
}
return results[0].value;
});
有没有办法告诉mongo根据匹配的字段进行条件更新?像这样:
db.collection('discussions').findOneAndUpdate({
$or: [{
teacherId: userId
}, {
studentId: userId
}],
_id
}, {
$set: {
// if field matched was studentId, set studentLastMessage
// if field matched was teacherId, set teacherLastMessage
}
});
肯定有可能使用mongo 3.2吗?
答案 0 :(得分:1)
您想要的是需要引用$set
内的其他字段。目前这是不可能的。请参阅this ticket作为示例。
首先,您当前使用两个更新查询的方法对我来说很合适。您可以继续使用它,只需确保您有正确的索引。也就是说,要获得这些更新的最佳性能,您应该有两个复合索引:
{ _id: 1, teacherId: 1 }
{ _id: 1, studentId: 1 }
。从另一个角度来看,您应该重构数据。例如:
{
_id: '...',
users: [
{
userId: '...',
userType: 'student',
lastMessage: 'lorem ipsum'
},
{
userId: '...',
userType: 'teacher',
lastMessage: 'dolor sit amet'
}
]
}
这将允许您使用单个查询执行更新。
答案 1 :(得分:1)
您的数据结构有点奇怪,除非您有一个特定的业务案例,需要按照我建议的方式创建一个usertype,除非用户既可以是教师也可以是学生,然后保留您的结构。
$set{}
param可以接受一个对象,我的建议是先做你的业务逻辑。在更新之前,您应该已经知道更新是针对教师还是学生 - 应该设置某种变量/认证级别以区分教师和学生。也许在成功登录回调后,您可以设置cookie /本地存储。无论如何 - 如果您拥有当前类型的用户,那么您可以更早地构建对象,因此根据用户类型创建具有所需属性的对象文字。
所以
if(student)
{
var updateObj = { studentLastMsg: msg }
}
else
{
var updateObj = { teacherLastMsg: msg }
}
然后传递$set{updateObj}
的更新,我会将其设为一个代码段 - 在移动设备上