Я пытаюсь сравнить 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, в котором переопределено множество методов массива. И вот как

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