【问题标题】:Node.js + MongoDB query not working properly with "$or" objectNode.js + MongoDB 查询无法与“$or”对象一起正常工作
【发布时间】:2012-03-16 17:41:04
【问题描述】:

我正在尝试为用户创建一条路径,以便能够检查其他用户的个人资料。但是,我希望通过 2 个不同的 URL /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 的新手,所以我不确定正确的方法是什么。

谢谢!

【问题讨论】:

  • 你用的是什么版本的mongo?
  • Mongo 版本如下:Marcos-Mellados-iMac-2:~ marcos$ mongod --version db version v2.0.2, pdfile version 4.5 Mon Feb 27 02:48:11 git version: 514b122d308928517f5841888ceaa4246a7f18e3

标签: node.js mongodb routes express


【解决方案1】:

默认 _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) { ........

问候芬奇!!!

【讨论】:

  • 如何定义 ObjectId?现在我有 mongoose = require('mongoose'), ObjectID = mongoose.Schema.ObjectId,
  • 忽略最后一条评论,他的做法的问题是,在将昵称作为参数发送并通过createFromHexString函数传递的那一刻,它会抛出下一个错误:错误:传入的参数必须可以是 12 字节的单个字符串或 24 个十六进制字符的字符串(例如,假设昵称是 finch)
  • 当然,尝试首先使用以下方法将您的字符串(Finch)转换为十六进制字符串:var hexString =nickname.toHexString(); - 然后将其作为参数传递以创建您的 objectID
【解决方案2】:

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

我不知道 node.js mongodb-driver 内部结构,但它可能会在查询“_id”字段之前尝试在内部将参数转换为 ObjectId(如果无效则失败)。我没有检查这个,所以试试看。还尝试检查回调上的 err 对象。如果这是问题,解决此问题的一种方法是在查询之前检查参数是否有效 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 );
}

【讨论】:

  • 我尝试在查询时打印错误代码。这就是我得到的:[错误:无效的 ObjectId],我的假设是当我尝试使用 Finch 作为参数时,条件通过 _id 部分,因为给定的字符串不是有效的 ObjectId,查询中断,返回错误...因此即使部分查询确实有效也不给出结果...关于如何解决此问题的任何想法?
  • @MarcosMellado 这似乎支持我的想法。我在帖子中提出了解决方案,我对其进行了修改以添加一些示例代码以使其更清晰。
  • 我实际上已经找到了一个非常相似的解决方案,我将对其进行适当的更改以使其与 try catch 一起使用,并让您知道它是否有效:)
  • 示例代码对我来说很有意义,但是,我得到 ReferenceError: ObjectID is not defined 我不确定原因,但这是我一段时间以来一直试图找出的。 ..如何创建对象ID:S
  • 在定义 Schema = mongoose.Schema, ObjectId = Schema.ObjectId 后,在我的 app.js 中我得到:500 错误:这是一个抽象接口。它的唯一目的是在架构创建中将字段标记为 ObjectId。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-25
  • 2014-02-01
  • 2017-12-30
  • 1970-01-01
  • 1970-01-01
  • 2012-04-05
  • 2021-08-26
相关资源
最近更新 更多