NEDB 查询在数组上使用 $nin 返回误报
NEDB Query returning false positives with $nin on array
我在使用 NEDB find()
查询结构时遇到问题。
下面的 find()
查询应该 return 所有新消息:发送到指定的 email
或 All
组并且尚未被阅读或发送的email
指定。
但是,它是 returning 误报。例如,尽管 email
IS 的数组中的 email
IS 属性 正在评估中。我正在使用 $nin
运算符,但我无法弄清楚我做错了什么?欢迎所有建议:)
var email = 'anotheraddress@gmail.com';
var message_query = [];
message_query.push({$and: [{to: 'All'}, {'data.readBy': {$nin: [email]}}]});
message_query.push({$and: [{to: email}, {'data.read': {$exists: false}}]});
message
.find({
$and: [
{$not: {from: email}},
{$or: message_query}
]
})
.exec(function (err, results) {
});
这是平面文件的片段。这两个不应该 returned,但它们是 :/
...
{
to: 'All',
toname: 'Some Name',
from: 'someaddress@gmail.com',
fromname: 'Some other Name',
message: 'A message for all...',
timestamp: 1502473320,
imtype: 'msg',
_id: 'K66iP3dZHbYTfGgK',
data:
{ readBy:
[ 'someotheraddress@gmail.com',
'anotheraddress@gmail.com' ] }
},
{
to: 'All',
toname: 'Some Name',
from: 'someoneelse@gmail.com',
fromname: 'Some other Name',
message: 'A message for all...',
timestamp: 1502473420,
imtype: 'msg',
_id: 'K66iP3dZNyNxfGgK',
data:
{ readBy:
[ 'someotheraddress@gmail.com',
'anotheraddress@gmail.com' ] }
}
...
提前致谢
问题出在 $nin
运算符 - 它不像在 mongo 中那样工作。
NEDB 的 $in
运算符的工作方式不同:只有一个操作数可以是数组。查看数组的 $in
($nin
is just a negation of $in
after all). When it checks if things are equal 定义,它确保只有一项是数组,即 a
或 b[i]
都不能是数组。如果是,则 return 为假。 $nin
因此 return 是正确的 - 解释了结果中两个文档的存在。
您可以按如下方式验证这一点:尝试将 [email]
更改为 ["someotheraddress@gmail.com", "anotheraddress@gmail.com", "foo@bar.com"]
之类的内容,您会注意到这两个结果消失了 - 证明它不会检查 data.readBy
不在我们提供的列表中,但请检查整个 data.readBy
是否存在于我们提供的列表中。
解决方法
使用 { $not: { elemMatch }
您可以通过将查询更改为以下内容来解决此问题:
message_query.push({
$and: [{ to: "All" }, { $not: { "data.readBy": { $elemMatch: email } } }]
});
验证代码如下:
const Datastore = require("nedb");
const db = new Datastore({
inMemoryOnly: true,
autoload: false
});
db.insert(
[
{
to: "All",
toname: "Some Name",
from: "someaddress@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473320,
imtype: "msg",
data: {
readBy: ["someotheraddress@gmail.com", "anotheraddress@gmail.com"]
}
},
{
to: "All",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
readBy: ["someotheraddress@gmail.com", "anotheraddress@gmail.com"]
}
},
{
to: "All",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
readBy: ["someotheraddress@gmail.com" ]
}
},
{
to: "foo@bar.com",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
readBy: ["someotheraddress@gmail.com", "anotheraddress@gmail.com"]
}
},
{
to: "anotheraddress@gmail.com",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
read: true
}
},
{
to: "anotheraddress@gmail.com",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
}
}
],
(...args) => {
var email = "anotheraddress@gmail.com";
var _list = ["someotheraddress@gmail.com", "anotheraddress@gmail.com", "foo@bar.com"];
var message_query = [];
message_query.push({
$and: [{ to: "All" }, { $not: { "data.readBy": { $elemMatch: email } } }]
});
// message_query.push({
// $and: [{ to: "All" }, { "data.readBy": { $nin: [email] } }]
// });
// message_query.push({
// $and: [{ to: "All" }, { "data.readBy": { $nin: _list } }]
// });
message_query.push({
$and: [{ to: email }, { "data.read": { $exists: false } }]
});
db.find({
$and: [ { $not: { from: email } }, { $or: message_query } ]
}).exec(function(err, results) {
console.log(JSON.stringify(results, null, 2));
});
}
);
我在使用 NEDB find()
查询结构时遇到问题。
下面的 find()
查询应该 return 所有新消息:发送到指定的 email
或 All
组并且尚未被阅读或发送的email
指定。
但是,它是 returning 误报。例如,尽管 email
IS 的数组中的 email
IS 属性 正在评估中。我正在使用 $nin
运算符,但我无法弄清楚我做错了什么?欢迎所有建议:)
var email = 'anotheraddress@gmail.com';
var message_query = [];
message_query.push({$and: [{to: 'All'}, {'data.readBy': {$nin: [email]}}]});
message_query.push({$and: [{to: email}, {'data.read': {$exists: false}}]});
message
.find({
$and: [
{$not: {from: email}},
{$or: message_query}
]
})
.exec(function (err, results) {
});
这是平面文件的片段。这两个不应该 returned,但它们是 :/
...
{
to: 'All',
toname: 'Some Name',
from: 'someaddress@gmail.com',
fromname: 'Some other Name',
message: 'A message for all...',
timestamp: 1502473320,
imtype: 'msg',
_id: 'K66iP3dZHbYTfGgK',
data:
{ readBy:
[ 'someotheraddress@gmail.com',
'anotheraddress@gmail.com' ] }
},
{
to: 'All',
toname: 'Some Name',
from: 'someoneelse@gmail.com',
fromname: 'Some other Name',
message: 'A message for all...',
timestamp: 1502473420,
imtype: 'msg',
_id: 'K66iP3dZNyNxfGgK',
data:
{ readBy:
[ 'someotheraddress@gmail.com',
'anotheraddress@gmail.com' ] }
}
...
提前致谢
问题出在 $nin
运算符 - 它不像在 mongo 中那样工作。
NEDB 的 $in
运算符的工作方式不同:只有一个操作数可以是数组。查看数组的 $in
($nin
is just a negation of $in
after all). When it checks if things are equal 定义,它确保只有一项是数组,即 a
或 b[i]
都不能是数组。如果是,则 return 为假。 $nin
因此 return 是正确的 - 解释了结果中两个文档的存在。
您可以按如下方式验证这一点:尝试将 [email]
更改为 ["someotheraddress@gmail.com", "anotheraddress@gmail.com", "foo@bar.com"]
之类的内容,您会注意到这两个结果消失了 - 证明它不会检查 data.readBy
不在我们提供的列表中,但请检查整个 data.readBy
是否存在于我们提供的列表中。
解决方法
使用 { $not: { elemMatch }
您可以通过将查询更改为以下内容来解决此问题:
message_query.push({
$and: [{ to: "All" }, { $not: { "data.readBy": { $elemMatch: email } } }]
});
验证代码如下:
const Datastore = require("nedb");
const db = new Datastore({
inMemoryOnly: true,
autoload: false
});
db.insert(
[
{
to: "All",
toname: "Some Name",
from: "someaddress@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473320,
imtype: "msg",
data: {
readBy: ["someotheraddress@gmail.com", "anotheraddress@gmail.com"]
}
},
{
to: "All",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
readBy: ["someotheraddress@gmail.com", "anotheraddress@gmail.com"]
}
},
{
to: "All",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
readBy: ["someotheraddress@gmail.com" ]
}
},
{
to: "foo@bar.com",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
readBy: ["someotheraddress@gmail.com", "anotheraddress@gmail.com"]
}
},
{
to: "anotheraddress@gmail.com",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
read: true
}
},
{
to: "anotheraddress@gmail.com",
toname: "Some Name",
from: "someoneelse@gmail.com",
fromname: "Some other Name",
message: "A message for all...",
timestamp: 1502473420,
imtype: "msg",
data: {
}
}
],
(...args) => {
var email = "anotheraddress@gmail.com";
var _list = ["someotheraddress@gmail.com", "anotheraddress@gmail.com", "foo@bar.com"];
var message_query = [];
message_query.push({
$and: [{ to: "All" }, { $not: { "data.readBy": { $elemMatch: email } } }]
});
// message_query.push({
// $and: [{ to: "All" }, { "data.readBy": { $nin: [email] } }]
// });
// message_query.push({
// $and: [{ to: "All" }, { "data.readBy": { $nin: _list } }]
// });
message_query.push({
$and: [{ to: email }, { "data.read": { $exists: false } }]
});
db.find({
$and: [ { $not: { from: email } }, { $or: message_query } ]
}).exec(function(err, results) {
console.log(JSON.stringify(results, null, 2));
});
}
);