ruby-on-rails - Ruby on Rails 和 NoSQL,添加字段

标签 ruby-on-rails mongodb mongoid

我刚刚开始研究 Mongodb 和 MongoID with Rails,我发现它很棒。 NoSQL 有帮助的一件事是,我可以随时向我的模型添加额外的字段,而无需任何额外的努力:

class Page
  include Mongoid::Document
  include Mongoid::MultiParameterAttributes
  field :title, :type => String
  field :body, :type => String
  field :excerpt, :type => String #Added later
  field :location, :type => String #Added later
  field :published_at, :type => Time

  validates :title, :presence => true
  validates :body, :presence => true
  validates :excerpt, :presence => true
end

这一切都完美无缺。但我的问题是,(对不起,如果这是微不足道的)现有条目是空白的,并且没有为新添加的字段定义值。例如,在一个示例博客应用程序中,在我发布了两篇文章之后,我决定向我的数据库中添加一个摘录和一个位置字段(请参阅上面的代码)。添加这些新字段后发布的任何博客文章都可以确保为摘录字段填充了一个值。但是在添加这两个新字段之前发布的帖子具有我无法验证的空值(这是可以理解的原因)。有没有一个优雅的解决方案?

谢谢。

最佳答案

共有三个基本选项:

  1. 更新 MongoDB 中的所有内容以包含摘录。
  2. 当您将现有对象从 MongoDB 中拉出时,使用 after_initialize Hook 将默认摘录添加到现有对象。
  3. 调整您的验证逻辑以仅检查新对象上是否存在摘录。

(1) 在您进行更改时需要(可能很长时间)点击,但这只是一次性的事情,之后您不必担心。您将从 MongoDB 中提取每个页面,执行 page.excerpt = 'some default excerpt',然后将其保存回 MongoDB。如果你有很多页面,你会希望以 block 的形式处理它们,比如一次处理 100 个。如果这样做,您将能够搜索摘录,而不必担心应该如何处理 null。您也可以通过发送 JavaScript fragment into MongoDB 在 MongoDB 中执行此操作:

connection.eval(%q{
    db.pages.find({}, { _id: true }).forEach(function(p) {
        db.pages.update(
            { _id: p._id },
            { $set: { excerpt: 'some default excerpt' } }
        );
    });
})

(2) 会像这样:

after_initialize :add_default_excerpt, :unless => :new_record?
#...
private
def add_default_excerpt
  self.excerpt = 'some default excerpt' unless self.excerpt.present?
end

如果您不介意使用 lambda,您可以将 unless self.excerpt 移至 :unless:

after_initialize :add_default_excerpt, :unless => ->{ |o| o.new_record? || o.excerpt.present? }
#...
private
def add_default_excerpt
  self.excerpt = 'some default excerpt'
end

这应该非常快速且容易设置,但也有缺点。首先,您的 MongoDB 中会有一堆 null,您可能需要在搜索期间对其进行特殊处理。此外,您会随身携带一堆代码和逻辑来处理旧数据,但随着时间的推移,这些包袱会越来越少。此外,after_initialize 调用不是免费的。

(3) 要求您跳过验证非新页面摘录的存在(:unless => :new_record?),否则您必须找到一些方法来区分新对象来自旧的,同时还正确处理新旧页面的编辑。您还可以强制人们在更改页面时提供摘录并按原样保留您的验证;在您的 field :excerpt 中包含一个 :default => '' 将处理 View 中的任何 nil 问题等。


如果可能的话,我会选择 (1)。如果更新时间太长,并且您希望在修复 MongoDB 时启动并运行站点,则可以在更新时添加 :default => '' 然后删除 :default 选项,重新启动,并手动修补任何通过的杂散。

关于ruby-on-rails - Ruby on Rails 和 NoSQL,添加字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9012865/

相关文章:

ruby-on-rails - 您正在尝试在 heroku-20 上安装 ruby​​-2.6.3

ruby-on-rails - simple_form 的 Rails 表单关联

java - MongoDB3.0查询到java的转换

mongodb - mongo_mapper 或 mongoid 与 Rails4

ruby-on-rails - Rails NoMethod错误: undefined method `name' for "#<RecipeType:0x000055cd000b18a0>":String

ruby-on-rails - 设计 valid_password 的奇怪问题?

java - 从 MongoDB 整理中获取不需要的输出

mongodb - MongoDB Keys Examined 意味着什么?

mongodb - 使用 mongoid 通过 json 返回别名字段

ruby-on-rails - 无法连接到副本集的主节点 <Moped::Cluster nodes=[<Moped::Node resolved_address ="127.0.0.1:27017">]>