获取新警报时,我想检查是否已记录新警报的ID。问题是该ID嵌套在数组中。有alertDetails数组,其中包含对象,并且那些对象具有_ID字段,这是我要检查的内容。我不确定如何实现这一目标。我得到下面的代码,但是然后我必须遍历结果以检查是否存在值。我肯定一定有更好的方法。
const mongoose = require('mongoose');
const { Schema } = mongoose;
const G2AlertsSchema = new Schema(
{
status: { type: String, required: true },
openDate: { type: Date, required: true },
alertType: { type: Array, required: true },
severity: { type: Array, required: true },
locationName: { type: Array, required: true },
history: { type: Array, required: true },
alertDetails: { type: Array, required: false },
assignedTo: { type: Schema.Types.ObjectId, ref: 'user' },
},
{
timestamps: true,
},
);
const G2Alerts = mongoose.model('G2Alert', G2AlertsSchema);
module.exports = G2Alerts;
这是我在mongodb网站上找到的代码。我只想查看ID是否仅存在。基本上,当我获取新警报时,会得到一个数组并对其进行迭代,因此我想对照数据库中的内容检查每个项目的ID。如果有,请跳过并转到下一个。如果是新警报,则创建一个新警报并保存。
const exists = await G2Alerts.aggregate([
{
$project: {
exists: {
$in: ['5f0b4f508bda3805754ab343', '$alertDetails._id'],
},
},
},
]);
编辑:另一件事。我收到警告,说我应该使用数组迭代而不是for循环。问题是,我在查找警报ID时需要使用await。如果我使用,减少或过滤,则无法使用await。如果我在reduce或filter函数中使用async,则它将在一个空数组中返回promise。
以下内容基于 Tom Slabbaert
提供的答案而起作用 const newAlertsData = [];
for (let item of alertData.data.items) {
const exists = await G2Alerts.find({ 'alertDetails._id': `${item._id}` });
if (exists.length === 0) {
newAlertsData.push(item);
}
}
if (newAlertsData.length !== 0) {......
但这不是
const filteredAlerts = alertData.data.items.reduce((filtered, item) => {
const exists = await G2Alerts.find({ 'alertDetails._id': `${item._id}` });
if (exists.length === 0) {
filtered.push(item);
}
return filtered;
}, []);
答案 0 :(得分:2)
相距不远,这是使用正确语法的示例:
const exists = await G2Alerts.findOne({"alertDetails._id": '5f0b4f508bda3805754ab343'}});
if (!exists) {
... do something
}
这也可以通过将aggregate
与$match
阶段一起使用,而不是$project
阶段,甚至更好的countDocuments来实现,它只返回计数而不是整个对象您不需要它。
我想补充的另一件事是,在您alertDetails._id
中使用string
时,请确保string
是$in
类型。否则,您需要将它们强制转换为ObjectId
类型的猫鼬:
new mongoose.Types.ObjectId('5f0b4f508bda3805754ab343')
对于Mongo:
import {ObjectId} from "mongodb"
...
new ObjectId('5f0b4f508bda3805754ab343')
编辑
尝试这样的事情?
let ids = alertData.data.items.map(item => item._id.toString());
let existing = await G2Alerts.distinct("alertsDetails._id", {"alertsDetails._id": {$in: ids}});
const filteredAlerts = alertData.data.items.reduce((filtered, item) => {
if (!existing.includes(item._id.toString())) {
return [item].concat(filtered)
}
return filtered;
}, []);
通过这种方式,您只需调用一次数据库,而无需多次调用。
基于提供的答案的最终代码。
const ids = alertData.data.items.map(item => item._id);
const existing = await G2Alerts.find({ 'alertDetails._id': { $in: ids } }).distinct(
'alertDetails._id',
(err, alerts) => {
if (err) {
res.send(err);
}
return alerts;
},
);
const filteredAlerts = alertData.data.items.reduce((filtered, item) => {
if (!existing.includes(item._id.toString()) && item.openDate > dateLimit) {
return [item].concat(filtered);
}
return filtered;
}, []);