Node.js + MongoDB查询与“$或”对象无法正常工作

时间:2012-02-27 08:12:56

标签: node.js mongodb routes express

我正在尝试为用户创建一条路径,以便能够检查其他用户的个人资料。但是,我希望通过2个不同的网址/profile/nickname/profile/id来加入这些个人资料,以便可以使用用户的昵称或用户ID来接收个人资料。我尝试了以下代码:

app.get("/profile/:id", function(req, res) {

User.findOne( { $or : [{ "nickname": req.params.id },{ "_id": req.params.id }] }, function(err, user) {
    if(user)
    {
        res.render('users/profile.jade', {
        locals: { 
            currentUser: user, 
            title: user.nickname +"'s Profile",
            jsf:[],
        }
        });
    }
    else
    {
        res.render('404.jade', { 
            status: 404,
            title: 'Page Not Found', 
                jsf: []  
        });
    }
});
});

问题是,它似乎只是使用id而不是昵称,这意味着如果我访问/profile/4f4ae474546708b219000005事情有效,但是如果我访问/profile/mmellad这是给定的昵称对于该用户,我获得了404页面。

我还想到了另一件可以解决昵称的问题,即改变查询

User.findOne( { $or : [{ "nickname": req.params.id },{ "_id": req.params.id }] }

User.findOne( { "nickname": req.params.id } }

在这种情况下/profile/mmellado工作正常,但显然没有使用用户ID。

这样做的正确方法是什么?我想我可能采用了错误的方法。

另外需要提及的是,如果我在mongo控制台中尝试以下代码,它也能正常工作:

x = db.users.findOne({ $or: [ {nickname:"mmellado"}, {_id:ObjectId("4f4ae474546708b219000005")}  ]})

我通过插入正确的昵称和错误的_id来测试该代码,然后使用错误的昵称和正确的_id进行测试。在这两种情况下,x最终都包含了我需要的记录对象。

我想我可以通过一条额外的路线修复它,但我是Node.js和Express的新手,所以我不确定这个方法是什么。

谢谢!

2 个答案:

答案 0 :(得分:4)

您是否在控制台中尝试了此操作:x = db.users.findOne({ $or: [ {nickname:"mmellado"}, {_id:ObjectId("mmellado")} ]})。即使昵称匹配,您也会看到错误,因为它首先尝试将“mmellado”转换为ObjectId并失败。这可能是您在使用昵称时页面失败的原因。

我不知道node.js mongodb-driver内部,但它可能会在查询“_id”字段之前尝试将参数内部转换为ObjectId(如果无效则会失败)。我没有检查过,所以试一试。还尝试检查回调上的错误对象。如果这是问题,解决这个问题的一种方法是在查询之前检查参数是否是有效的ObjectId,例如自己创建ObjectId并在失败时捕获异常。这样的事情(未经测试):

try {
  var objectId = createObjectId(req.params.id); // Create this function yourself
  User.findOne( { "_id": objectId }, callbackFunction );
} catch (err) {
    // Fall back to using nickname
    User.findOne( { "nickname": req.params.id }, callbackFunction );
}

答案 1 :(得分:0)

默认的_id值是12字节的二进制哈希值,因此在使用ObjectID.createFromHexString发送查询之前,首先需要将字符串转换为二进制:

var id = ObjectID.createFromHexString(idHex);

然后在查询中使用id。

您的代码应如下所示:

User.findOne( { $or : [{ "nickname": req.params.id },{ "_id": ObjectID.createFromHexString(req.params.id) }] }, function(err, user) { ........

问候芬奇!!!