我在试着比较req.user._id其中包含从MongoDB查询返回的ObjectIds数组。但全部.includes()、严格和宽松的相等性检查失败。
下面是我的控制器中的逻辑(为了简单起见,将其截断):
// Get the ID of the document from the request
const someDocId = req.body.id;
// Perform the search with projection
const result = await Some_DB.findById(someDocId,{adminIds:1, _id:0}).lean();
/*
The structure of the query result is as the following:
{
adminIds: [ 5f77ba7d1a0fba8f5e811e76, 6035f2e7174d4961808944d1 ],
}
And req.user._id is equal to 6035f2e7174d4961808944d1
*/
// When I do
console.log(result.adminIds[1] === req.user._id);
console.log(result.adminIds[1] == req.user._id);
console.log(result.adminIds.includes(req.user._id))
// I also tried
const { ObjectId, } = require('mongoose').Types
console.log(result.adminIds[1] === ObjectId(req.user._id));
console.log(result.adminIds[1] == ObjectId(req.user._id));
console.log(result.adminIds.includes(ObjectId(req.user._id)))
// The result is always false
// Additional Info:
(the results below are the same with or without .lean()
const { ObjectId, } = require('mongoose').Types
const a = sphereInfo.adminIds[1];
const b = req.user._id;
console.log(a instanceof ObjectId); // => true
console.log(b instanceof ObjectId); // => true
console.log(typeof(result.adminIds[1])); // => object
console.log(typeof(req.user._id)); // => object
console.log(result.adminIds[1]);
// 6035f2e7174d4961808944d1 (note:there is no single quote around)
console.log(req.user._id);
// 6035f2e7174d4961808944d1 (note:there is no single quote around)
const a = Object.values(sphereInfo.adminIds[1]);
const b = Object.values(req.user._id);
console.log(a); // => [ 'ObjectID', ]
console.log(b); // => [ 'ObjectID', ]
const a = Object.getOwnPropertyNames(sphereInfo.adminIds[1]);
const b = Object.getOwnPropertyNames(req.user._id);
console.log(a); // => [ '_bsontype', 'id' ]
console.log(b); // => [ '_bsontype', 'id' ]
console.log(Object.entries(sphereInfo.adminIds[1]));
console.log(Object.entries(req.user._id));
/*
Result:
[
[ '_bsontype', 'ObjectID' ],
[ 'id', ]
]
[
[ '_bsontype', 'ObjectID' ],
[ 'id', ]
]
*/
console.log(JSON.stringify(sphereInfo.adminIds[1]));
console.log(JSON.stringify(req.user._id));
/*
Result:
"6035f2e7174d4961808944d1"
"6035f2e7174d4961808944d1"
*/// After removing .lean()
console.log(result.adminIds[1] === req.user._id); // => false
console.log(result.adminIds[1] == req.user._id); // => false
console.log(result.adminIds.includes(req.user._id)) // => true模式(为简单起见进行了截断):
// Dependencies
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const SomeSchema = new Schema({
adminIds: [{
type: Schema.Types.ObjectId,
ref: 'user',
}],
}, {
collection: 'SomeCollection',
timestamps: true,
});
module.exports = { SomeSchema, };无论我如何看待它,它们都是完全相同的。但是,所有.includes()、严格和松散相等检查返回false。更让我困惑的是,对象结构是相同的,不管有没有.lean()如果我删除.lean()从查询中,所有检查仍然失败,仅.inclides()返回true。
根据Mongoose的说法Doc:
lean选项告诉Mongoose跳过合并结果文档。这使得查询速度更快,占用的内存更少,但是结果文档是普通的旧式JavaScript对象(POJO),而不是Mongoose文档。默认情况下,Mongoose查询返回Mongoose Document类的一个实例。文档比普通的JavaScript对象要重得多,因为它们有很多用于更改跟踪的内部状态。启用lean选项会告诉Mongoose跳过实例化完整的Mongoose文档,只提供POJO。
该文档还提到,启用精益的缺点是精益文档没有:
我在任何地方都看不到.lean()可能会影响相等性检查,也会影响.includes()方法。所以最后的问题是谁能给我解释一下.lean()导致相等检查失败,但.includes通过?注意:我不是问如何比较它们,以便检查通过,但如何.lean()导致检查失败,但`.includes()通过。
发布于 2021-02-25 04:11:45
差异是微妙的,但它是存在的。使用.lean()您的查询最终使用数组解析result.adminIds;需要注意的是,这个数组的每个元素都是ObjectId --正如@codemonkey正确提到的,它仍然是ObjectId --一个对象。当您尝试使用以下命令在该数组中查找特定的ObjectId时includes,搜索只会因为引用不相等而失败。
但是,当按原样执行查询时,.lean()已应用,result.adminIds不再只是一个数组-它是MongooseArray这实际上覆盖了很多数组方法。这就是为什么Mongoose.prototype.indexOf(用于MongooseArray.prototype.includes)看起来像:
indexOf(obj, fromIndex) {
if (obj instanceof ObjectId) {
obj = obj.toString();
}
fromIndex = fromIndex == null ? 0 : fromIndex;
const len = this.length;
for (let i = fromIndex; i < len; ++i) {
if (obj == this[i]) {
return i;
}
}
return -1;
}正如您所看到的,这里的第一步是将第一个参数(如果它是ObjectId)转换为字符串,基本上消除了引用检查。这就是为什么includes应该既适用于直接字符串比较,也适用于ObjectId one。
但最有趣的部分如下:==(和not===)在查找中使用时,存储在该数组中的ObjectId值在与string进行比较时被转换为基元。这就是为什么即使直接比较能给你false,includes()实际上为您提供了方便的(但令人困惑的,真实的)解决方法。
发布于 2021-02-25 03:19:55
我不完全确定为什么文档坚持他们是POJO,但你得到的结果确实与MongoDB ObjectID对象。也许他们说它们是POJO,因为它们不是由相关的构造函数构造的,它们只是传递给新对象的属性。
您想要比较str如果要比较在控制台上看到的十六进制值,请使用。
console.log(result.adminIds[1].str === req.user._id.str);否则,您将比较两个不同的对象(始终为false)。
检查结果为真的唯一方法是:
console.log(result.adminIds[1] === req.user._id);如果它们都是相同的对象,或者它们都是相同的字符串。
在我看来
我不会调用一个扩展的对象valueOf和/或toString一个POJO,因为它本质上扩展了JS对象的一些功能。因此,不再简单。
发布于 2021-02-25 03:23:26
lean()将返回ObjectId,但是POJO的值仍然是Object类型。您自己的测试结果证实:
console.log(typeof(result.adminIds[1])); // => object
console.log(typeof(req.user._id)); // => object因此,要比较这两个值,只需进行如下比较:
console.log(result.adminIds[1].toString() === req.user._id.toString());至少这是我一直在做的事情,它总是有效的。
https://stackoverflow.com/questions/66356976
复制相似问题