1

由于 Mongoid API 没有使 MongoDB $sample 操作可见,我不得不使用 Mongo 驱动程序手动运行查询,我不知道如何处理结果。

我有不同的类/集合,它们遵循一些通用接口(出于多种原因,我不想使用继承),并且我试图将它们呈现为单个集合。我有一个从这三个类中采样的代码

entries = [Class1, Class2, Class3].inject([]) do |array, clazz|
  entries << clazz.collection.aggregate([ { '$sample': { size: 10 } } ])    
end

这给了我三个不同的数组Mongo::Collection::View::Aggregation。我想以某种方式合并这些并能够实例化对象,以便我可以在我的视图中使用它们(例如使用单元格)

<%= cell(:profile, collection: entries) %>

Usingentries.to_a将返回一个哈希数组,而不是一个(模型)对象数组。我希望会是这样,然后我会使用单元格生成器来处理模型之间的其余细微差异

builds do |model, options|
    case model
    when Class1; Class1Cell
    when Class2; Class2Cell
    when Class3; Class3Cell
  end

编辑 :

我实际上仍然可以使用to_a和使用密钥_type来找到相应的常量/模型。true现在蝾螈的问题是如何用哈希实例化一个模型,它不会返回new_record?

sample = entries.to_a.first
  instance = Utility.resolve_class(sample[:_type]).new(entry_hash)
  # Problem is...
  instance.new_record? # => returns true, but since it comes from the DB it means it has already been persisted so it should return false.
4

3 回答 3

1

Cells 适用于任何 PORO。因此,实现您想要的最简单的方法是创建一个类来表示您在模型文件中想要的数据。只需将其创建为普通的 ruby​​ 类。您可以隐藏数据查询方法以创建聚合并将一组类作为类方法返回。

类似的东西(你需要整理一下,这只是一个让你开始的技巧):

# some PORO
class Record
   attr_accessor :field_1, :field_2, :field_3

   def self.build
       # your existing code
       entries = [Class1, Class2, Class3].inject([]) do |array, clazz|
        entries << profile_collection.collection.aggregate([ { '$sample': { size: 10 } } ])    
       end

       array_of_objects = []

       # now for each record within the aggregate create an object
       entries.each do |obj|
          new_poro = self.new
          obj.keys.each do |key|
             new_poro.self.instance_variable_set(key, obj[key])
          end
          array_of_objects.push new_poro
       end  
       return array_of_objects 
    end
end


# to run it in your controller
@records_in_objects_for_cells = Record.build

# in your views
<%= cell(:record, collection: records_in_objects_for_cells %>
于 2016-04-18T21:33:54.833 回答
1

要回答您编辑的问题,您可以将其设置为 false。变量是 new_record ,如此处所示(http://www.rubydoc.info/github/mongoid/mongoid/Mongoid/Stateful:new_record%3F)。

所以:

r = MongoRecord.find_by(x:y)
e = r.new(e)
e.new_record?
=> true
e.new_record = false
e.new_record? 
=> false

MongoId 使用这个标志来知道它是否被持久化。如果发生持久性事件,它使用 _id 来了解要更新的记录。

于 2016-04-18T22:19:56.623 回答
1

最好的方法是使用Mongoid::Document类方法instantiate

Person.instantiate(document)
# or even
Person.instantiate({firstname: 'John', lastname: 'Doe'})

或者对于您的示例:

entries = [Class1, Class2, Class3].inject([]) do |array, clazz|
  entries << clazz.collection.aggregate([
    { '$sample': { size: 10 } }
  ]).map do |document|
    clazz.instantiate(document)
  end    
end

如描述中所述:

实例化一个新对象,仅当从数据库加载或属性已经被类型转换时。

此外,它selected_fields作为第二个参数,它有助于让它知道只有给定的字段已经从数据库中加载。

于 2018-07-11T11:51:39.857 回答