Чи можу я визначити, чи є рядок MongoDB ObjectID?


81

Я виконую пошук в MongoDB, перетворюючи рядок у BSON. Чи можу я перед перетворенням визначити, чи є рядок, який я маю, дійсним ObjectID для Mongo?

Ось coffeescript для моєї поточної функції findByID. Це чудово працює, але я хотів би шукати за іншим атрибутом, якщо визначу, що рядок не є ідентифікатором.

db.collection "pages", (err, collection) ->
  collection.findOne
    _id: new BSON.ObjectID(id)
  , (err, item) ->
    if item
      res.send item
    else
      res.send 404

На даний момент використання блоку try catch працює. Це рекомендоване рішення?
Буде

Відповіді:


145

Я виявив, що мангустський валідатор ObjectId працює для перевірки дійсних ідентифікаторів об’єктів, але виявив кілька випадків, коли недійсні ідентифікатори вважалися дійсними. (наприклад: будь-який рядок довжиною 12 символів)

var ObjectId = require('mongoose').Types.ObjectId;
ObjectId.isValid('microsoft123'); //true
ObjectId.isValid('timtomtamted'); //true
ObjectId.isValid('551137c2f9e1fac808a5f572'); //true

Для мене працювало приведення рядка до objectId, а потім перевірка відповідності вихідного рядка рядковому значенню objectId.

new ObjectId('timtamtomted'); //616273656e6365576f726b73
new ObjectId('537eed02ed345b2e039652d2') //537eed02ed345b2e039652d2

Це працює, оскільки дійсні ідентифікатори не змінюються при приливанні до ObjectId, але рядок, який отримує помилково дійсний, змінюється при відливанні до objectId.


Теоретично ви можете додати ці два методи, щоб згенерувати неймовірно добрий валідатор ObjectID, це буде зроблено сьогодні.
Ентоні

2
Отже, щось подібне? function checkObjectIdValid(id){ if(ObjectID.isValid(id)){ if(new ObjectID(id) === id){ return true } else { return false } } else { return false } }
Джексон Воган,

Щось подібне могло б спрацювати, або порівняння рядків за допомогою функції ObjetcId toString.
Енді Маклеод,

2
Насправді відповідь @JacksonVaughan майже правильна. Для перетворення нового ObjectID (id) у рядок не було String (), оскільки ми порівнюємо його з іншим рядком. Ось повна правильна відповідь: const ObjectId = require('mongoose').Types.ObjectId; function isObjectIdValid(id) { if (ObjectId.isValid(id)) { if (String(new ObjectId(id)) === id) { return true } else { return false } } else { return false } }
marcvander

1
@marcvander дозвольте мені es6це зробити для вас:isObjectIdValid = id => ObjectId.isValid(id) ? String(new ObjectId(id) === id) ? true : false : false;
Rod911,

82

Ви можете використовувати регулярний вираз, щоб перевірити це:

CoffeeScript

if id.match /^[0-9a-fA-F]{24}$/
    # it's an ObjectID
else
    # nope

JavaScript

if (id.match(/^[0-9a-fA-F]{24}$/)) {
    // it's an ObjectID    
} else {
    // nope    
}

1
Хм, це також може збігатися з не-objectIds, найкращий спосіб - це або створити валідатор на основі специфікації, і регулярно виразити його конкретні частини, або спробувати створити новий об'єктив і розмістити блок catch, щоб зловити, якщо він може це зробити.
Sammaye

2
@Sammaye Це та сама перевірка, яка використовується конструктором BSON ObjectID . Чи можете ви дати мені приклад рядка, який не відповідає ObjectID, якому він відповідав би?
JohnnyHK

Ого, я не бачив, що це прийде. Ну будь-який рядок із 24 символів, у якому є цифри та літери, тобтоlol456712bbfghLLsdfr
Sammaye

13
@Sammaye Але це дійсний ObjectID, тому він повинен збігатися.
JohnnyHK

1
Можливо, вірний шлях, офіційно запропонований mongoose github.com/Automattic/mongoose/issues/…
Akarsh Satija

10

Раніше я використовував власний драйвер mongodb для вузла. Метод isValid перевіряє, чи є значення дійсним BSON ObjectId. Дивіться документацію тут.

var ObjectID = require('mongodb').ObjectID;
console.log( ObjectID.isValid(12345) );

здається, не працює, вище повертає true для випадкового числа.
Dan Ochiana,

1
Я думаю, що це, швидше за все, тому, що так повинно бути ObjectId, а не ObjectID. :)
Кен Хофф,

це повинна бути прийнята відповідь, не потрібно мангуста
FH

5

Якщо ви використовуєте Mongoose, ми можемо перевірити, чи має рядок 12 байт або рядок з 24 шістнадцяткових символів, використовуючи вбудований mongoose isValidObjectId .

mongoose.isValidObjectId (рядок) поверне true / false

Це модернізоване рішення, яке надається прийнятим рішенням .


серйозно, давайте проголосуємо за цю справу. Стара прийнята відповідь була чудовою, коли бібліотека не підтримувала цього, але зараз це робить. Обійти це - хак, який залежить від деталей реалізації.
lance.dolan

4

Ось деякий код, який я написав на основі відповіді @ andy-macleod.

Він може приймати або int, або рядок, або ObjectId, і повертає дійсний ObjectId, якщо передане значення є дійсним, або null, якщо воно недійсне:

var ObjectId= require('mongoose').Types.ObjectId;

function toObjectId(id) {

    var stringId = id.toString().toLowerCase();

    if (!ObjectId.isValid(stringId)) {
        return null;
    }

    var result = new ObjectId(stringId);
    if (result.toString() != stringId) {
        return null;
    }

    return result;
}

3

mongoose.Types.ObjectId.isValid (рядок) завжди повертає значення True, якщо рядок містить 12 літер

let firstUserID = '5b360fdea392d731829ded18';
let secondUserID = 'aaaaaaaaaaaa';

console.log(mongoose.Types.ObjectId.isValid(firstUserID)); // true
console.log(mongoose.Types.ObjectId.isValid(secondUserID)); // true

let checkForValidMongoDbID = new RegExp("^[0-9a-fA-F]{24}$");
console.log(checkForValidMongoDbID.test(firstUserID)); // true
console.log(checkForValidMongoDbID.test(secondUserID)); // false

2

Єдиний спосіб, який я знайшов, це створити новий ObjectId зі значенням, яке я хочу перевірити, якщо вхідні дані дорівнюють вихідним, ідентичний ідентичний:

function validate(id) {
    var valid = false;
    try
    {
        if(id == new mongoose.Types.ObjectId(""+id))
           valid = true;

    }
    catch(e)
    {
       valid = false;
    }
    return valid;
}

> validate(null)
false
> validate(20)
false
> validate("abcdef")
false
> validate("5ad72b594c897c7c38b2bf71")
true

1

Найпростіший спосіб - в основному обернути метод ObjectId у службі try and catch. Тоді ви використовуєте цю послугу для обробки ідентифікаторів Objecet, замість того, щоб використовувати метод безпосередньо:

var ObjectId = REQUIRE OR IMPORT ...

// service
function oid(str) {
 try {   
   return ObjectId(str);
 } catch(err) {
   return false;
 }
}

// usage
if (oid(USER_INPUT)) {
  // continue
} else {
  // throw error
}

Ви також можете надіслати нульовий або порожній реквізит, щоб отримати новий згенерований ідентифікатор.


1

Найпростіший спосіб перевірити, чи є рядок дійсним Mongo ObjectId, - за допомогою модуля mongodb .

const ObjectID = require('mongodb').ObjectID;

if(ObjectID.isValid(777777777777777)){
   console.log("Valid ObjectID")
}

1

Нижче наведена функція, яка одночасно перевіряє за допомогою isValidметоду ObjectId і чи new ObjectId(id)повертає одне і те ж значення. Причину isValidнедостатньої самотності Енді Маклеод дуже добре описав у вибраній відповіді.

const ObjectId = require('mongoose').Types.ObjectId;

/**
 * True if provided object ID valid
 * @param {string} id 
 */
function isObjectIdValid(id){ 
  return ObjectId.isValid(id) && new ObjectId(id) == id;
}

Дякуємо за огляд. Я оновив опис
AliAvci

2
Це не буде працювати, оскільки ви робите суворе порівняння між рядком та ідентифікатором об’єкта. Будь ласка, оновіть до подвійних рівних.
Маттіа Расуло

0

Якщо у вас є шістнадцятковий рядок, ви можете використовувати це:

ObjectId.isValid(ObjectId.createFromHexString(hexId));

0

Мені знадобився деякий час, щоб отримати дійсне рішення, оскільки запропоноване @Andy Macleod порівняння значення objectId зі своїм рядком призвело до збою сервера Express.js на:

var view_task_id_temp=new mongodb.ObjectID("invalid_id_string"); //this crashed

Я просто використав просту спробу улову, щоб вирішити це.

var mongodb = require('mongodb');
var id_error=false;
try{
    var x=new mongodb.ObjectID("57d9a8b310b45a383a74df93");
    console.log("x="+JSON.stringify(x));
}catch(err){
    console.log("error="+err);
    id_error=true;
}

if(id_error==false){
   // Do stuff here
}

0

Для мангуста використовуйте функцію isValid (), щоб перевірити, чи є objectId дійсним чи ні

Приклад:

var ObjectId = mongoose.Types.ObjectId;
if(ObjectId.isValid(req.params.documentId)){
   console.log('Object id is valid'); 
}else{
   console.log('Invalid Object id');
}

0

У розчині відповідь Енді Маклеод сказав:

Для мене працювало приведення рядка до objectId, а потім перевірка відповідності вихідного рядка рядковому значенню objectId.

new ObjectId('timtamtomted'); //616273656e6365576f726b73
new ObjectId('537eed02ed345b2e039652d2') //537eed02ed345b2e039652d2

Це працює, оскільки дійсні ідентифікатори не змінюються при приливанні до ObjectId, але рядок, який отримує помилково дійсний, змінюється при відливанні до objectId.

Реалізація цього підходу буде функцією, яка перевіряє, чи передане значення є дійсним ObjectIdі працює з обома значеннями stringта ObjectId(об'єкт). Це виглядало б приблизно так:

var ObjectId = require("mongoose");.Types.ObjectId;

function isValidObjectId(value) {
  // If value is an object (ObjectId) cast it to a string
  var valueString = typeof value === "string" ? value : String(value); 

  // Cast the string to ObjectId
  var idInstance = new ObjectId(valueString); 

  return String(idInstance) === valueString;
}

0

Відповідь @ ross-u просто вражає.

Я прив'язав методи до повної перевірки вбудовано:

documentId = id && isValid(id) && new ObjectId(id) == id ? id : null

Зверніть увагу на подвійний знак рівності, який ДУЖЕ важливий, оскільки new ObjectId() не повертає рядок, а суворе порівняння поверне значення false при порівнянні зі звичайним рядком (що я мав на увазі в своїй логіці).

Методи були деструктуровані з mongooseоб'єкта, що зазнав дії:

const {
  Types: {
    ObjectId: { isValid },
    ObjectId
  }
} = require("mongoose");

-2

Попередження: isValid поверне true для довільних рядків довжиною 12/24, що починаються з дійсної шістнадцяткової цифри. На даний момент я думаю, що це краща перевірка:

((thing.length === 24 || thing.length === 12) && isNaN(parseInt(thing,16)) !== true)


3
Це оцінювало б trueдля 'funky string'. Будь-який рядок правильної довжини, який починається з шістнадцяткової цифри, задовольнить його.
JohnnyHK
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.