【问题标题】:Issue with mongoId's any_of implementation for activerecordmongoId 对 activerecord 的 any_of 实现问题
【发布时间】:2016-01-12 11:57:08
【问题描述】:

我有这样的设置模型数据

[52] pry(main)> Setting.all.to_a
    => [#<Setting _id: 561cc75b25917fdc2300003c, courses: ["521c4578ef8b6038ba000069", "55f909c825917f1ac000003e"], user_id: "55f908d725917f5157000036">,
     #<Setting _id: 563b322425917f8117000025, courses: ["561cddbb25917fa26e0000b9", "5614e62225917fbb1300005f", "5617a6bd25917f7aa100005d", "560ca6b325917f158d000002", "5617a5f325917ff38c000036", "5632eebc25917f1ace000038", "55f909c825917f1ac000003e", "521c4578ef8b6038ba000069"], user_id: "56125d7b25917fb8c0000001">,
     #<Setting _id: 5641d3b125917fa02f000009, courses: ["5614e62225917fbb1300005f", "55f909c825917f1ac000003e", "521c4578ef8b6038ba000069"], user_id: "5264b629ef8b604f96000001">,
     #<Setting _id: 565d541925917f10da000013, courses: ["561cddbb25917fa26e0000b9", "5614e62225917fbb1300005f", "5617a6bd25917f7aa100005d", "5617a5f325917ff38c000036", "560ca6b325917f158d000002", "55f909c825917f1ac000003e", "5632eebc25917f1ace000038", "521c4578ef8b6038ba000069"], user_id: "565d53f525917f10da000012">]

现在我想要一组具有特定课程的设置

    pry(main)> course = Course.find("5614e62225917fbb1300005f")
    pry(main)> Setting.any_of(courses: course.id).to_a
=> [#<Setting _id: 565d541925917f10da000013, courses: ["561cddbb25917fa26e0000b9", "5614e62225917fbb1300005f", "5617a6bd25917f7aa100005d", "5617a5f325917ff38c000036", "560ca6b325917f158d000002", "55f909c825917f1ac000003e", "5632eebc25917f1ace000038", "521c4578ef8b6038ba000069"], user_id: "565d53f525917f10da000012">]

它只产生了一个不是预期结果的数组元素,然后

[53] pry(main)> Setting.any_of(courses: course.id.to_s).to_a
=> [#<Setting _id: 563b322425917f8117000025, courses: ["561cddbb25917fa26e0000b9", "5614e62225917fbb1300005f", "5617a6bd25917f7aa100005d", "560ca6b325917f158d000002", "5617a5f325917ff38c000036", "5632eebc25917f1ace000038", "55f909c825917f1ac000003e", "521c4578ef8b6038ba000069"], user_id: "56125d7b25917fb8c0000001">,
 #<Setting _id: 5641d3b125917fa02f000009, courses: ["5614e62225917fbb1300005f", "55f909c825917f1ac000003e", "521c4578ef8b6038ba000069"], user_id: "5264b629ef8b604f96000001">]

产生两个数组元素,但期望的结果是三个数组元素,可以通过将这两个结果相加或通过以下语法来获得

[57] pry(main)> Setting.any_of({courses: course.id.to_s}, {courses: course.id}).to_a
=> [#<Setting _id: 563b322425917f8117000025, courses: ["561cddbb25917fa26e0000b9", "5614e62225917fbb1300005f", "5617a6bd25917f7aa100005d", "560ca6b325917f158d000002", "5617a5f325917ff38c000036", "5632eebc25917f1ace000038", "55f909c825917f1ac000003e", "521c4578ef8b6038ba000069"], user_id: "56125d7b25917fb8c0000001">,
 #<Setting _id: 5641d3b125917fa02f000009, courses: ["5614e62225917fbb1300005f", "55f909c825917f1ac000003e", "521c4578ef8b6038ba000069"], user_id: "5264b629ef8b604f96000001">,
 #<Setting _id: 565d541925917f10da000013, courses: ["561cddbb25917fa26e0000b9", "5614e62225917fbb1300005f", "5617a6bd25917f7aa100005d", "5617a5f325917ff38c000036", "560ca6b325917f158d000002", "55f909c825917f1ac000003e", "5632eebc25917f1ace000038", "521c4578ef8b6038ba000069"], user_id: "565d53f525917f10da000012">]

我的困惑是为什么

Setting.any_of(courses: course.id).to_a

Setting.any_of(courses: course.id.to_s).to_a

产生不同的结果,我的第三种语法方法是获得我想要的结果的唯一正确方法吗?

【问题讨论】:

    标签: ruby-on-rails arrays ruby mongoid


    【解决方案1】:

    我不能 100% 确定,因为我真的不知道您的数据库中有什么。不过,我对这里的问题很有信心。

    由于您没有分享您的设置模型定义,我猜想是这样的:

    class Setting
      include Mongoid::Document
      field :courses, type: Array
    end
    

    如果这不正确,请告诉我,我会更新答案。鉴于这种结构,看看这个撬动会话:

    [4] pry(main)> string_id = "563b322425917f8117000025"   
    => "563b322425917f8117000025"
    [5] pry(main)> object_id = Moped::BSON::ObjectId.from_string("563b322425917f8117000025")   
    => "563b322425917f8117000025"
    [6] pry(main)> string_id.class.name   
    => "String"
    [7] pry(main)> object_id.class.name   
    => "Moped::BSON::ObjectId"
    

    请注意Moped::BSON::ObjectId 适用于 Mongoid 3(我碰巧在这里安装的那个)。在较新的版本中,它只是 BSON::ObjectId,因为 Mongoid 4+ 放弃了 Moped gem。

    我们可以创建两个不同的对象来表示同一个标识符。一个是 String 实例,另一个是 Moped::BSON::ObjectId 类,在 Mongoid 内部用于表示同一事物,即 Mongo ObejctId。

    为了让事情变得更简单,Mongoid(和 mongo 本身)允许您在某些情况下使用字符串而不是 ObjectId,但并非总是如此。在某些情况下,与上述 Setting 类一样,它无法知道您是否要将 String 实例或 ObjectId 实例保存到数据库中。因此,它将保存您发送到的任何内容:

    [10] pry(main)> st = Setting.new(:courses => [object_id])
    => #<Setting _id: 5694ff9a04572eeb16000001, courses: ["563b322425917f8117000025"]>
    [11] pry(main)> st.save
    => true
    [12] pry(main)> st2 = Setting.new(:courses => [string_id])
    => #<Setting _id: 5694ffa904572eeb16000002, courses: ["563b322425917f8117000025"]>
    [13] pry(main)> st2.save
    => true
    [14] pry(main)> Setting.where(:courses => string_id).to_a
    => [#<Setting _id: 5694ffa904572eeb16000002, courses: ["563b322425917f8117000025"]>]
    [15] pry(main)> Setting.where(:courses => string_id).to_a == [st2]
    => true
    [17] pry(main)> Setting.where(:courses => object_id).to_a == [st]
    => true
    

    因此,变量st 指向一个Setting 对象,该对象保存有一个包含一个ID 的课程字段,表示为Moped::BSON::ObjectId 实例,而st2 包含相同ID 的纯字符串表示。所以,这两件事看起来是一样的,而且很难发现,因为 Moped::BSON::ObjectID#to_s 方法返回的 id 与 String#to_s 完全相同,所以如果你尝试将它打印到 shell 会话中,你将无法发现差异.要发现差异,您必须致电 object_id.class.name 并与 string_id.class.name 进行比较。

    您可以通过运行以下命令来证明您是否属于这种情况:

    all_settings = Setting.any_of({courses: course.id.to_s}, {courses: course.id})
    all_settings.each do |a_setting|
      puts "Setting #{a_setting.id}:"
    
      a_setting.courses.each do |string_or_object_id|
        puts "   #{string_or_object_id.class.name} #{string_or_object_id}"
      end
    end
    

    理想情况下,您应该在此数组中仅使用 String 对象或仅使用 ObjectId 对象,否则您将来会遇到问题。要解决这个问题。我建议您使用Moped::BSON::ObjectId,因为它映射到自然的 ObjectId Mongo 表示,并允许您做一些有趣的事情,例如按生成日期查询 ObjectId:

    [21] pry(main)> object_id.generation_time
    => 2015-11-05 10:40:36 UTC
    

    我希望这会有所帮助:)

    【讨论】:

    • 我还建议包含一个before_validation 挂钩,将courses 中的所有条目转换为ObjectId,并进行验证以确保它们确实都是ObjectId。迟早会有东西在那里放一个字符串。
    • 非常感谢您提供如此清晰的解释,解决了我每次更新设置时将字符串转换为 ObjectId 的问题 Moped::BSON::ObjectId.from_string(course_id) 感谢@muistooshort 的提醒
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多