Могу ли я определить, является ли строка идентификатором объекта MongoDB?

81

Я выполняю поиск в MongoDB, преобразовывая строку в BSON. Есть ли способ определить, является ли имеющаяся у меня строка действительным идентификатором объекта для 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. Это рекомендуемое решение?
Will

Ответы:

145

Я обнаружил, что валидатор mongoose 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 } }
Джексон Воан
Что-то подобное сработает, или сравнение строк с использованием функции toString ObjetcId.
Энди Маклауд
2
На самом деле ответ @JacksonVaughan почти правильный. Не хватало String () для преобразования нового ObjectID (id) в строку, поскольку мы сравниваем его с другой строкой. Вот полный правильный ответ: 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    
}
JohnnyHK
источник
1
Хм, это также может соответствовать не-objectIds, лучший способ - либо создать валидатор на основе спецификации и регулярного выражения для его конкретных частей, либо попытаться создать новый objectid и разместить блок catch, чтобы поймать, если он может это сделать.
Sammaye
2
@Sammaye Это та же проверка, которая используется конструктором BSON ObjectID . Можете ли вы дать мне пример строки, отличной от ObjectID, которой она будет соответствовать?
JohnnyHK
Вау, я этого не ожидал. Ну, любая 24-символьная строка, в которой есть цифры и буквы, то естьlol456712bbfghLLsdfr
Sammaye
13
@Sammaye Но это действительный ObjectID, поэтому он должен совпадать.
JohnnyHK
1
Вероятно, правильный путь, официально предложенный mongoose github.com/Automattic/mongoose/issues/…
Акарш Сатия
10

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

var ObjectID = require('mongodb').ObjectID;
console.log( ObjectID.isValid(12345) );
Cbaigorri
источник
похоже, не работает, выше возвращает true для случайного числа.
Дэн Очиана 08
1
Я думаю, что это скорее всего, потому что так должно быть ObjectId, а не ObjectID. :)
Кен Хофф
это должен быть принятый ответ, мангусты не нужны
FH
5

Если вы используете Mongoose, мы можем проверить, имеет ли строка 12 байтов или строку из 24 шестнадцатеричных символов, используя встроенный в mongoose isValidObjectId .

mongoose.isValidObjectId (string) вернет 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;
}
Nzjoel
источник
3

mongoose.Types.ObjectId.isValid (string) всегда возвращает 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 в службу «попробуй и поймай». Затем вы используете эту службу для обработки идентификаторов Objecet Id вместо прямого использования метода:

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));
pkarc
источник
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)

iss42
источник
3
Это будет оценивать trueдля 'funky string'. Ему подойдет любая строка подходящей длины, начинающаяся с шестнадцатеричной цифры.
JohnnyHK