Я пытаюсь сравнить req.user._id
с массивом ObjectIds, возвращаемым из запроса MongoDB. Но все .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', <Buffer 60 35 f2 e7 17 4d 49 61 80 89 44 d1> ]
console.log(b); // => [ 'ObjectID', <Buffer 60 35 f2 e7 17 4d 49 61 80 89 44 d1> ]
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', <Buffer 60 35 f2 e7 17 4d 49 61 80 89 44 d1> ]
]
[
[ '_bsontype', 'ObjectID' ],
[ 'id', <Buffer 60 35 f2 e7 17 4d 49 61 80 89 44 d1> ]
]
*/
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()
.lean()
.lean()
.inclides()
Согласно Документу Mongoose:
Опция Lean указывает Mongoose пропустить увлажнение документов результатов. Это делает запросы более быстрыми и менее ресурсоемкими, но результирующие документы представляют собой простые старые объекты JavaScript (POJO), а не документы Mongoose. По умолчанию запросы Mongoose возвращают экземпляр класса Mongoose Document. Документы намного тяжелее обычных объектов JavaScript, потому что у них много внутреннего состояния для отслеживания изменений. Включение опции Lean указывает Mongoose пропустить создание полного документа Mongoose и просто предоставить вам POJO.
В документе также упоминается, что обратная сторона включения Lean заключается в том, что в документации Lean нет:
- Отслеживание изменений
- Кастинг и проверка
- Геттеры и сеттеры
- Виртуальные
- спасти()
.lean()
.includes()
.lean()
.includes
.lean()
1
Aviv Lo
24 Фев 2021 в 21:42
3 ответа
Лучший ответ
Разница небольшая, но она существует. С .lean()
ваш запрос в конечном итоге разрешается с массивом в result.adminIds
; предостережение в том, что каждый элемент этого массива является ObjectId, который, как правильно упомянул @codemonkey, остается ObjectId - объектом. И когда вы пытаетесь найти конкретный ObjectId в этом массиве с помощью includes
, поиск просто должен завершиться ошибкой из-за неравенства ссылок.
Однако, когда запрос выполняется как есть, без применения .lean (), result.adminIds больше не является просто массивом - это MongooseArray, в котором переопределено множество методов массива. И вот как
2
raina77ow
24 Фев 2021 в 20:50
Я не совсем уверен, почему в документации утверждается, что они являются объектами POJO, но результаты, которые вы получаете, совпадают с MongoDB ObjectID. Может быть, они говорят, что являются объектами POJO, потому что они не создаются соответствующими конструкторами, а являются просто свойствами, передаваемыми новому объекту.
Вы хотите сравнить свойство str
, если хотите сравнить шестнадцатеричное значение, которое вы видите на своей консоли.
console.log(result.adminIds[1].str === req.user._id.str);
В противном случае вы сравниваете два разных объекта (что всегда неверно).
Единственный способ проверить это верно:
console.log(result.adminIds[1] === req.user._id);
Было бы, если бы они оба были одним и тем же объектом или оба были одной строкой.
На мой взгляд
Я бы не стал называть объект, расширяющий valueOf
и / или toString
POJO, поскольку он существенно расширяет НЕКОТОРЫЕ функциональные возможности объектов JS. Следовательно, больше не просто.
1
MinusFour
24 Фев 2021 в 20:18
lean()
вернет POJO, но значения ObjectId по-прежнему будут иметь тип 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());
По крайней мере, то, что я всегда делаю, и это всегда работает.
1
codemonkey
24 Фев 2021 в 19:23