MongoDB 求教,请问如何让一些 field 不被 render 出来

kevinzhow · 2012年10月08日 · 最后由 knwang 回复于 2012年10月17日 · 3412 次阅读

嗯,事情是这样的 现在我把 Ember.js 和 rails 以及 mongodb 一起用,所以需要把一些数据以 json 发送到前台交给 emberjs 但是,比如我传递@user的时候,用@user.to_json 然后他会把一些比如用户 private_token 之类的 field 也发出来了,有没有什么方法来限定下某些 field 不传出来。 但是需要保证@user.field的时候还能读到这个 field? 谢谢!

#1 楼 @congteng 谢谢啦,it can work

我喜欢 DHH 写的 jbuilder https://github.com/rails/jbuilder

给你另外一个自己解决的思路...

如果情况不复杂,且需求相对固定, 可以 在 model 重写 as_json 方法。 如果情况比较复杂,可以加一层 presenter 层。 something like:

app/presenters/post_presenter.rb

class PostPresenter
  attr_reader :user, :post

  def initialize(user, post)
    @user = user
    @post = post
  end

  def as_json(options = { })
    post_hash = {
      title: @post.title,
      ...
      ...
    }

    post_hash
  end
end

Controller 里调用的时候可以这样

@posts = Post.all.map{ |p| PostPresenter.new(current_user, p) }

当然情况越是复杂,presenter 这种模式就越好用... 如果不复杂显得有点过了 :)

不是可以这样么 user.to_json(:only => ["created_at", "email"]) 或者 user.to_json(:except => ["_id","updated_at"]).

#5 楼 @karma +1 to_json 有很多参数的的,比如 only,method 之类的,可以看看 API

#5 楼 @karma 可以,这样只能 handle 相对简单的情况,比如你不一定只是包含对象的属性在 json。而且,这样你 controller 很快就膨胀了,如果你几个 controller 都需要 user.to_json 你每个地方或许都要做同样的 only 或者 except.

#6 楼 @edokeh #5 楼 @karma 毕竟 only 等等 option 是特殊要求

#7 楼 @poshboytl 😄 我是看您的视频长大的啊! 添加对象不包含的属性的话,我都直接这样写 user["name"] = "karma", 然后再 to_json 当然了,我的需求确实比较简单.


既然逮到您了,就搭车问您个问题吧,先说说我的需求: 接收用户上传的某个 csv 文件, 对文件的数据逐行处理,并将处理之后的数据存入数据库 (mongo) 我现在是一次性读入整个文件,然后逐行读出,处理,存储,类似这样

CSV.foreach(file_path, :headers => true) do |row|
  result = row.do_sth
  #====== 分割 ======#
  c = Cellection.new
  c.field = result
  c.save
end

但是特别的慢啊,3000 条的数据就需要十几秒了, 时间主要花费在了分割线以下的部分, 而且跑了几次之后 mongo 得内存占用就高得离谱,是不是我对 orm 得使用方法不科学啊,求解决思路


还有几个风格上得问题请教, Ruby 提倡写短方法, 但是写多了之后 model 会特别的乱, 这些方法该怎么组织呢? 不少 model 已经几千行了, 是不是过大了呢? 方法调用的层级越高效率会不会越慢呢, 相似的还有类得数量与 new 对象 (是否) 过多的问题... 新人求教啊,谢谢!

#7 楼 @poshboytl 同意你的看法,还是要看使用的场景,如果项目中有特别多需要 json 的地方,或者生成 json 的过程中包含了一些 “业务逻辑” 的话,to_json 确实有些单薄了 这时候这层逻辑放到 model 中确实是比较好的一种方式

#9 楼 @karma 晕....哈哈~ :D 你这个情况 资源和时间的消耗主要是大量的插入 DB 造成的.. 我用 activerecord 比较多...遇到大量的插入我会使用 https://github.com/zdennis/activerecord-import 效果非常明显...

不太确定是否 mongo 有同样的东西,你搜搜看看? :)

你的第二个问题,是个很大的问题。我试着来回答你一下。 你的 model 过胖有几个问题需要思考。

  1. 这个逻辑是否应该在 model,有没有可以分离出来的部分。 由于大家天天听 胖 model 瘦 controller,导致很多人把一些应该在 controller 里的逻辑也放在 model 了:比如像发送一封邮件,比如 mass assignment 的 checking。 再如有些 callback 里的逻辑是不是可以放在 observer 里。像我前面提到的,如何呈现数据是不是可以抽出一层 presenter 层。

  2. 有些不紧密和 model 相关的逻辑并且有重用空间的是不是可以抽出一个 module 放在其他的位置。

  3. 如果你单个方法就很长你就要考虑是否有可重用的部分要抽取成多个方法。(我们一般极少有方法会超过 50 行)

如果以上问题你都做好了,那说明这个 model 就该这么大... :D 也没什么需要惊慌的....

#9 楼 @karma 插入操作的话,如果用的是mongoid这个 gem 的话,是不是用createsave方法好?刚去看了下文档发现,save是一个update or insert操作,而create的话直接就是insert

ps:我刚才本地测试的结果,大约 5k 条数据,每条数据有 20 个字段,循环插入前时间是1349681854,结束时间是1349681880,也没你说的那么慢啊,

ActiveRecord的话我一般都用ActiveRecord.create方法,这个能传个 hash 的数组进去直接 insert

#11 楼 @poshboytl 第二个问题我再好好思考一下,检查下代码,看看需要怎么调整


第一个问题的到了圆满的解决, 原来 mongoid 本身就支持批量的插入,使用了这个之后秒速插入了 http://stackoverflow.com/questions/3772378/batch-insert-update-using-mongoid

batch = [{:name => "mongodb"}, {:name => "mongoid"}]  
Article.collection.insert(batch)

其实我应该先 Google 一下的, 当时翻了下文档,没能解决就直接提问了,实在是惭愧...

最后谢谢 @poshboytl, railscasts-china 每期必看的, 实在是太喜欢 ruby, 太喜欢这个社区了~

#12 楼 @ywjno#13 楼吧...或许是 mongo 连接比较占用资源吗?批量插入后相当迅速了... ps 有些对不住楼主@kevinzhow 了,楼完全被我歪了.. 见谅啊

#4 楼 @poshboytl 谢啦,其实这个正是我最想要的方式,而且效率应该也更高一些

#13 楼 @karma #11 楼 @poshboytl

- 5~8 行可以开始考虑 extract method; 十几行的就要开始想 extract class 了。 - 建议测试先行。如果测试先行的写出几十行的代码是很难的 - 对于逻辑过于复杂的解决方案是增加对象

需要 登录 后方可回复, 如果你还没有账号请 注册新账号