我可以确定字符串是否为MongoDB ObjectID吗?


79

我正在通过将字符串转换为BSON进行MongoDB查找。在转换之前,有没有办法让我确定我拥有的字符串是否是Mongo的有效ObjectID?

这是我当前的findByID函数的脚本。效果很好,但是如果我确定字符串不是ID,我想按其他属性查找。

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块是可行的。这是推荐的解决方案吗?
2012年

Answers:


140

我发现猫鼬的ObjectId验证程序可用来验证有效的objectId,但我发现了一些无效ID被视为有效的情况。(例如:任意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

这项工作是因为有效的id强制转换为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

81

您可以使用正则表达式进行测试:

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,最好的方法是根据规范和正则表达式的特定部分构建验证器,或者尝试制作新的objectid并容纳catch块以进行捕获(如果可以的话)。
Sammaye

2
@Sammaye这与BSON ObjectID构造函数使用的验证相同。您能给我一个与之匹配的非ObjectID字符串的示例吗?
JohnnyHK

哇,我没想到 那么任何包含数字和字母的24字符串,即lol456712bbfghLLsdfr
Sammaye 2012年

13
@Sammaye但这是一个有效的ObjectID,因此应该匹配。
JohnnyHK


9

我过去曾使用本机节点mongodb驱动程序来执行此操作。isValid方法检查该值是否为有效的BSON ObjectId。请参阅此处的文档。

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

似乎不起作用,以上返回的随机数为true。
丹·奥奇亚娜

1
我认为最有可能是因为它应该这样做ObjectId,而不是ObjectID。:)
肯霍夫

4

这是我根据@ andy-macleod的答案编写的一些代码。

它可以采用int或string或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,则可以使用isValidObjectId来测试String是12个字节还是24个十六进制字符的字符串。

mongoose.isValidObjectId(string)将返回true / false

这是公认解决方案提供的升级解决方案


2

我发现的唯一方法是使用要检查的值创建一个新的ObjectId,如果输入等于输出,则id有效:

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

2

如果字符串包含12个字母,则mongoose.Types.ObjectId.isValid(string)始终返回True

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

1

最简单的方法基本上是将您的ObjectId方法包装在try and catch服务中。然后,您将使用此服务来处理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
}

您也可以发送空道具或空道具以获得新的生成ID。


1

检查字符串是否为有效的Mongo ObjectId的最简单方法是使用mongodb模块。

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

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

1

下面是一个函数,该函数同时检查ObjectIdisValid方法以及是否new ObjectId(id)返回相同的值。isValid安迪·麦克劳德(Andy Macleod)在所选答案中很好地描述了一个人不够孤独的原因。

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
当您在字符串和对象ID之间进行严格比较时,此方法将无效。请更新为等于两倍。
Mattia Rasulo

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

我只是用一个简单的try catch来解决这个问题。

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

解决方案答案中,安迪·麦克劳德(Andy Macleod)说:

对我有用的是将字符串强制转换为objectId,然后检查原始字符串是否与objectId的字符串值匹配。

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

这项工作是因为有效的id强制转换为ObjectId时不会更改,但是获取错误的有效字符串将强制转换为objectId时会更改。

此方法的实现将是一个函数,该函数检查传递的值是否有效,ObjectId并与stringObjectId(对象)值一起使用。它看起来像这样:

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。

方法已从mongooserequire暴露的对象中解构:

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

-2

警告:isValid对于以有效十六进制数字开头的任意12/24长度的字符串将返回true。目前,我认为这是一个更好的检查:

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


3
这将评估true'funky string'。任何长度合适且以十六进制数字开头的字符串都可以满足要求。
JohnnyHK 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.