【问题标题】:Rails + Mongoid - Don't return nil values in JSONRails + Mongoid - 不要在 JSON 中返回 nil 值
【发布时间】:2012-01-04 16:23:47
【问题描述】:

我在 Mongoid 中有很多可选字段,例如:

  field :key, type: String             
  field :element, type: String         
  field :rect, type: Array             

如果我返回这个模型的 json 并且只填充其中一个,我会在所有其他字段上得到 null 值。如何删除这些字段?

我的模型有嵌套属性,这意味着空值可以在多个级别上。

说明:

我需要一种方法从模型的 json 表示中删除空字段,包括所有嵌套属性中的空字段。

代码示例

1.9.3-p0 :005 > u=Muse.new(:key=>'ram').to_json
 => "{\"_id\":\"4f1ced749c2ee4219d000003\",\"element\":null,\"key\":\"ram\",\"rect\":null}" 

【问题讨论】:

  • 一些示例数据/预期的输入/输出在这里会有所帮助
  • 在模型上调用 to_json 时效果很好。 json 对象没有任何空字段?您使用的是哪个版本的 mongoid?调用 your_doc_obj.to_json 时返回 null 吗?
  • 它确实有空字段。示例中仅填充了一个字段,其他字段为空,我想将它们删除。我还想删除其他字段(但我将使用 :attr_protected 删除)
  • @myxospsm,您必须使用Muse.new(:key=>'ram').as_json.reject! {|k,v| v.nil?} 而不是Muse.new(:key=>'ram').to_json 才能获得正确的结果。这就是我在回答中所说的。请运行Muse.new(:key=>'ram').as_json.reject! {|k,v| v.nil?},让我知道你得到了什么......
  • 是的,显然它可以工作(虽然我必须为嵌套属性编写一个函数)但它还是有点蹩脚,我希望有一种更清洁的方式。

标签: ruby-on-rails ruby mongodb mongoid


【解决方案1】:

默认情况下mongoid 可以删除空字段。如果您让某些字段为空,mongoid 将在插入时将其删除。

在下面的示例中,我省略了字段元素和矩形

class User
  include Mongoid::Document

    field :key, type: String             
    field :element, type: String         
    field :rect, type: Array       

    embeds_one :home  
end
>> u=User.new(:key=>'ram').to_json
=> "{"_id":"4f1c3722b356f82e4a000001","_type":"key":"ram"}"

而且效果很好。但是如果你在字段中输入一个 nil 值

>> u=User.new(:key=>'ram',:element=>nil).to_json
=> "{"_id":"4f1c3722b356f82e4a000001","_type":"User","key":"ram","element":null}"

它被插入。我认为这是您代码中的确切问题。因此,您可以通过使用 as_json 转换 JSON 哈希表示并删除 nil 字段来解决此问题

x=u.as_json.reject! {|k,v| v.nil?}
=> "{"_id":"4f1c3722b356f82e4a000001","_type":"User","key":"ram"}"

但是要进入内部级别,您不能使用as_json。检查下面的代码

  >>h=Home.new(:address=>'xxxx',:dummy=>nil)
  >>u.home = h 
  >>x=u.as_json.reject! {|k,v| v.nil?}
  =>{"_id"=>BSON::ObjectId('4f1c39b4b356f82e4a000003'), "_type"=>"User","key":"ram","home"=>#<Home _id: 4f1c3c5db356f82e4a000004,address:'xxxx' , dummy: nil >}

现在您看到嵌入式文档屋内的字段虚拟对象仍为 nil。所以我最好的建议是不要将 nil 值放在 db 中。为此,在您的模型(也嵌入)上放置一个before_save 回调并删除空字段。

我还将向您展示如何从嵌套对象中删除 nil 字段。没有别的办法就用它

我们可以使用 mongoid 模型的attributes 来获取包含嵌套层级的对象的哈希表示

x=u.attributes
=> {"_id"=>BSON::ObjectId4f1c39b4b356f82e4a000003,"key"=>"ram","element"=>nil,"home"=>{"address"=>"xxxx", "_id"=>BSON::ObjectId4f1c3c5db356f82e4a000004,"dummy"=>nil}}

你必须找到 mongoid 对象中是否有任何哈希,如果有,我们也必须在该哈希上使用reject! {|k,v| v.nil?}

把所有东西放在一起

def to_json(obj)
     obj.reject! {|k,v| v.nil?}
     obj.find_all {|x| x[1].class==BSON::OrderedHash}.each do |arr| 
           obj[arr[0]] = to_json(arr[1])    
     end
     obj     
end

并使用模型的属性调用它,

 >> to_json u.attributes
 => {"_id"=>BSON::ObjectId4f1c39b4b356f82e4a000003,"key"=>"ram","home"=>{"address"=>"xxxx", "_id"=>BSON::ObjectId4f1c3c5db356f82e4a000004}}

仅此而已。希望对你有帮助

【讨论】:

  • 谢谢!这听起来很合理,递归哈希是我最终所做的,但它很糟糕,我提出了赏金来寻找另一种方法。我明天会测试它,但这条线似乎是错误的:""{"_id":"4f1c3722b356f82e4a000001","_type":"key","fname":"ram"}"" - fname 是什么?
  • @myxospsm,这是一个错字...我把我的原始测试数据弄混了:(
  • 对不起,它不起作用。 Mongoid 自动将 null 值放入模型中。也许我会使用动态字段。 (示例出在问题中)
  • 您使用的是哪个版本的mongoid?因为我的例子来自 mongoid 2.2.4。但这不是问题。您是否运行了我的自定义 to_json 方法?你得到了什么?仍然是空值。请运行它并添加结果..我相信它应该可以工作,无论 mongoid 版本如何
【解决方案2】:

如果您只是想在将 JSON 发送到浏览器之前从查询结果中删除具有 nil 值的字段键,您可以简单地执行此操作(在我的情况下有效):

doc = Model.all.entries.map {|d| d.as_document}
respond_width(doc)

【讨论】:

    【解决方案3】:

    据我所知,Mongoid 本身没有这样的功能。 我的建议是使用其中一个 API 生成器:

    http://fabrik42.github.com/acts_as_api/

    https://github.com/nesquena/rabl

    https://github.com/rails/jbuilder

    【讨论】:

    • 我以前看过acts_as_api,但我不明白它是如何解决空删除问题的。
    • 您基本上有一些用于编写 JSON 响应的业务规则。因此,除非您想手动编写代码(这肯定是可能的),否则最好使用其中一种解决方案,恕我直言。
    【解决方案4】:

    如果您使用的是active_model_serializers,这很容易做到(查看this Railscast 以获得快速介绍)。

    对于您的用例,您可以编写如下所示的muse_serializer.rb

    class MuseSerializer < ActiveModel::Serializer
      def attributes
        muse = super
        object.attributes.each do |attr|
          muse[attr[0]] = attr[1]
        end
        muse.delete('_id') #in case you want to exclude the _id field
        muse
      end
    end
    

    这将返回当前 Muse 对象中存在的所有非空字段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-21
      • 2017-03-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多