【问题标题】:mongoose $or with mixed string and _id (ObjectId) not workingmongoose $或混合字符串和_id(ObjectId)不起作用
【发布时间】:2017-06-04 18:01:27
【问题描述】:

我正在尝试创建一种方法来从文档库中获取与 _id 匹配的“页面” permalink

以下代码示例返回猫鼬错误:

'对于模型“pages”的路径“_id”处的值“hello-world”,转换为 ObjectId 失败'

现在,如果 case 是“hello-world”或任何其他字符串永久链接,那么显然查询不是 ObjectId。那么在这种情况下我该如何使用 $or 呢,还是有更聪明的方法呢?

/**
 * Describes methods to create, retrieve, update, and delete pages
 * @returns void
 */
function Pages() {
    this.pages = require('../models/pages')
    this.users = require('../models/users')
    require('mongoose').connect(require('../../config/database/mongodb').url)
}

/**
 * Retrieve a page by permalink or id
 * @param {string} pageQuery - id or permalink
 * @callback {function} cFunction
 */
Pages.prototype.getOne = function(pageQuery, cFunction) {
    this.pages.findOne({$or: [{ 'permalink': pageQuery }, { '_id': pageQuery }] })
    .populate('author', 'email')
    .select('title permalink body author')
    .exec(function(error, result) {
        if (error) {
            cFunction(error)
            return
        }
        cFunction(result)
    })
}

页面模型

const mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId,
    pages = new Schema({
        title: { type: String },
        permalink: { type: String, unique: true },
        body: { type: String },
        author: { type: ObjectId, ref: 'users' },
        createdAt: { type: Date },
        revisedAt: { type: Date }
    })
    .index({
        title: 'text',
        permalink: 'text',
        body: 'text'
    })
    module.exports = mongoose.model('pages', pages)

用户模型

const mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId,
    users = new Schema({
        email: { type: String, unique: true },
        username: { type: String, unique: true },
        password: { type: String },
        createdAt: { type: Date }
    })
    .index({
        email: 'text',
        username: 'text'
    })
module.exports = mongoose.model('users', users)

【问题讨论】:

  • 看起来像pageQuery 传入的当前值是"hello-world"。我认为您正在调试某些东西并忘记在某处删除变量声明。因此出现错误。
  • @NeilLunn 我在我的问题中为页面和用户添加了模型。是的,我在测试中查询“hello-world”,但这就是重点。我希望能够从文档库中检索 id OR permalink 与查询匹配的页面,该查询可以是 id 或 permalink。
  • 是的,我撤回了这一点,因为您显然将该字符串作为输入提供给该函数。 “搜索你的代码,你就知道这是真的”
  • @NeilLunn 是的,我 am 提供该字符串 (hello-world) 作为方法参数,这正是我希望能够做到的......我不是确定你的意思tbh...
  • 我的意思是这是错误的原因。 Mongoose 正试图像这样“投射”ObjectId("hello-world"),因为它正在寻找具有默认 Schema.types.ObjectId_id。如果您打算匹配数据库中实际上是“字符串”_id: "hello-world"_id 值,那么您需要在架构中将 _id 定义为“字符串”。但我不认为你真的想要那样,这只是一个愚蠢的错误。\

标签: node.js mongodb mongoose


【解决方案1】:

看起来如果你运行new ObjectId(pageQuery) 并且它不是一个有效的 ObjectId,它会抛出一个错误告诉你(即错误:传入的参数必须是 12 个字节的单个字符串或 24 个十六进制字符的字符串。 )

这么说,我只想在Pages.prototype.getOne 的开头使用一个try/catch 块来尝试转换一个pageQueryOid 变量,如果你到达catch 块,你就知道这是因为pageQuery 不是一个有效的ObjectId。

使用此方法,您不再需要 $or 过滤器,而是可以根据 pageQuery 是否为有效的 ObjectId 来构建您的精确过滤器。以下只是其外观的一个示例,但您可以对其进行更新以满足您的需求:

Pages.prototype.getOne = function(pageQuery, cFunction) {
    var ObjectId = require('mongoose').Types.ObjectId
    var pageQueryOid
    try {
      pageQueryOid = new ObjectId(pageQuery)
    } catch(err) {
      console.log("pageQuery is not a valid ObjectId...")
    }

    var filter
    if (pageQueryOid) {
      filter = { '_id': pageQueryOid }
    } else {
      filter = { 'permalink': pageQuery }
    }

    this.pages.findOne(filter)
    .populate('author', 'email')
    .select('title permalink body author')
    .exec(function(error, result) {
        if (error) {
            cFunction(error)
            return
        }
        cFunction(result)
    })
}

【讨论】:

    猜你喜欢
    • 2017-11-05
    • 2019-03-12
    • 2015-03-25
    • 2017-08-20
    • 2015-01-17
    • 1970-01-01
    • 2021-02-15
    • 2014-07-30
    • 2018-06-25
    相关资源
    最近更新 更多