Skip to content

Question: How to use fields from other models to build the map method? #20

@marcocanderle

Description

@marcocanderle

Hello, I'm trying to implement a collection snapshot for a model that records transactions between people and which have certain limits that when reached, issues some alerts. These are the models:

class Transaction
     field :trx_type, type: String
     field :date, type: Date
     field :city, type: String
     belongs_to :account # emits transaction
     belongs_to :person  # receives transaction
end

class Limit
  field :limit_exceeded, type: Boolean, default: false
  field :year, type: Integer
  field :city, type: String
  field :cycle_type
  field :trx_tp, type: String
  belongs_to :account
  belongs_to :person 
end

To make a long story short, the idea here is that we would calculate the sum of the accumulated transactions for a given account/person pair, but that limit can be yearly (using year field) or by city (using the city field). So if cycle_type is :per_year, we use the year field to group the transactions and do the mapping, otherwise if it is :per_city, we use the city field instead.

What I don't know is how to use one or the other field in the map method, using cycle_type to decide, which is a field on the Limit model, and not the Transaction model I'm mapping. Note that any account/person pair will have the corresponding Limit object already created so at the moment of building the map, that information is already available.
But, how could I use some conditional mapping or any decision when mapping, in order to use one field or the other so that I can build the correct mapping with the correct fields set? That way when reading the values from the snapshot I can query them correctly, given the account/person pair for which we want the to check the calculated limit.

Here's my current, still unfinished, snapshot code:

 class CumulativeSnapshot
  include Mongoid::CollectionSnapshot

   document do
     belongs_to :person, inverse_of: nil
     belongs_to :account, inverse_of: nil
     field :year, type: Integer
     field :city, type: String
     field :trx_type, type: String
     field :sum, type: Integer
   end

   def build
      map = <<-EOS
       function() {
         emit({ year: this['date'].getFullYear(), person_id: this['person_id'], account_id: this['account_id'], trx_type: this['trx_type'], city: this['city'] }, { sum: this['amount']['cents'] })
       }
     EOS

     reduce = <<-EOS
       function(key, values) {
         var sum = 0;
         values.forEach(function(value) {
           sum += value['sum'];
         });
         return({ sum: sum });
       }
     EOS

     Transaction.map_reduce(map, reduce).out(inline: 1).each do |doc|
       collection_snapshot.insert_one(
         person_id: doc['_id']['person_id'],
         account_id: doc['_id']['account_id'],
         city: doc['_id']['city'],
         year: doc['_id']['year'],
         trx_type: doc['_id']['trx_type'],        
         sum: doc['value']['sum']
       )
     end
   end

Do you think there's a way of using the Limit#cycle_type on the map method to make a decision?

Otherwise, I was thinking of building 2 separate snapshots, one with the city field, and another snapshot with the year field, but wanted to check if there is any cleaner solution first, hence this question.

Thanks in Advance!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions