2017-07-08 2 views
3

InocmesExpensesのコレクションはアプリ全体で多くの場所で別々に使用されています。以下の要件を持つページは1つだけです。私は実際に何百万ものユーザーを持つ、MongoDBのには回避策はありません信じていません:(2つのコレクションをマージしてタイムスタンプを付けたデータを表示し、リアルタイム結果を表示

私は、プロジェクトで反応-流星を使用していますIncomesExpensesという名前の2つのコレクションを持っている。

下記のような所得のドキュメントを見て時間に基づいて
{ 
    "_id" : "euAeJYArsAyFWLJs6", 
    "account" : "3m5Zxsije9b6ZaNpu", 
    "amount" : 3, 
    "receivedAt" : ISODate("2017-07-07T06:21:00.000Z"), 
    "type" : "project", 
    "project" : { 
     "_id" : "ec2WLt3GzHNwhK7oK", 
     "name" : "test" 
    }, 
    "owner" : "nM4ToQEbYBsC3NoQB", 
    "createdAt" : ISODate("2017-07-07T06:21:37.293Z") 
} 

と費用ドクは、今私は、私はすべてのトランザクション(収入と支出)を示さなければならない取引と呼ばれるページを持っている

{ 
    "_id" : "snWDusDbkLHHY2Yry", 
    "account" : "3m5Zxsije9b6ZaNpu", 
    "amount" : 4, 
    "spentAt" : ISODate("2017-07-07T06:21:00.000Z"), 
    "description" : "4", 
    "category" : { 
     "_id" : "vh593tw9dZgNdNwtr", 
     "name" : "test", 
     "icon" : "icon-icons_tution-fee" 
    }, 
    "owner" : "nM4ToQEbYBsC3NoQB", 
    "createdAt" : ISODate("2017-07-07T06:22:04.215Z") 
} 

どのように見えるか、以下のトランスのためので、私の出版コード私はここに、トランザクションページにページネーションを実装する必要があり、データが日付でソートする必要があるまで、アクションはすべてのものの作業罰金ここティル

import { Meteor } from 'meteor/meteor'; 
import { Incomes } from '../../incomes/incomes.js'; 
import { Expenses } from '../../expences/expenses.js'; 
import { Counter } from 'meteor/natestrauser:publish-performant-counts'; 


let datefilter = (options, query) => { 
    let dateQuery = {$gte: new Date(options.dateFilter.start), $lte: new Date(options.dateFilter.end)}; 
    let temp = {$or: [{receivedAt: dateQuery}, {spentAt: dateQuery}]}; 
    query.$and.push(temp); 
}; 
Meteor.publish('transactions', function(options) { 
    let query = { 
     owner: this.userId, 
     $and: [] 
    }; 

    if(options.accounts.length) 
     query['account'] = {$in: options.accounts}; 

    options.dateFilter && datefilter(options, query); 
    //here i also apply other filter based on category and project which does not matter so i removed 

    if(!query.$and.length) delete query.$and; 

    //computing 'Transactions' below 
    return [ 
     Incomes.find(query, { 
      sort: { 
       receivedAt: -1 
      }, 
      limit: options.limit, 
      skip: options.skip 
     }), 
     Expenses.find(query, { 
      sort: { 
       spentAt: -1 
      }, 
      limit: options.limit, 
      skip: options.skip 
     }) 
    ] 
}); 

以下のように見えます。それが本当の問題です。私の両方のコレクションにはそれぞれ10レコードあり、テンプレートページには最初の10の結果が含まれていると仮定して、スキップ0と制限10を返すため、10の収入と10の費用レコードが返され、2ページ目にスキップとリミット両方のために10を送った。どのようにそれに対処するには?私はカウンターテクニックも使用しましたが、うまくいきませんでした。私のデータもリアルタイムであることを忘れないでください。 任意のヘルプは大歓迎されます:)

+0

からの結果は、あなたは、単に、実際に単に最初の場所でコレクションを「マージ」で、あなたの問題を解決することができます。私があなただったら、私はまさにそれを行うには、代わりに単に各コレクション内の項目に「費用」の「利益」のための「タイプ」と1を追加し、それらをマージします。それ以外では、何を求めていることは、結果の「労働組合」の上にソートやページングとSQL UNIONクエリのようなものです。実際にこれに直接関係するMongoDB操作はありません。実際には、ほとんどのまともなオプションとしてそのソースでコレクションをマージ残す、 –

+0

はマップが削減使用して、「マージ」という用語を説明してください||集計するか、2つのコレクションを削除して、1つのコレクションを完全に作成しますか? –

+0

私はもっとわかります。 MongoDBは、あなたが望む方法で、クエリのための2つのソースからのデータをマージする方法はありません。両方のコレクションを組み合わせた「新しいコレクション」を実際に作成する必要があります。そう、はい。2人を取り除き、1人にする。それで問題はない。 –

答えて

2

これは、迅速な参加問題について一時的な解決策である、あなたは あなたのデータセット量を考慮すべきであるとの前にすべてのチェックに合格した私は@NeilLunnとして私のスキーマを変更しますその間を適用まもなく移行を提案し、計画します。

ディスプレイ要件を満たすアドホックフィックスでは、の組み合わせでaggregateを適用しました。今

Meteor.publish('transaction', function(options){ 
    //here I perform many filter based on query and options 
    //which deleted to shorten code on SO 

    //call asynchronous method just to get result delay :) 
    Meteor.call('copyTransactions', (err, res) => { 
     //something do here 
    }); 
    //note the we return results from **Transactions** which is comes as third collection 
    return [ 
     Transactions.find(query, { 
      sort: sortbyDate, 
      skip: options.skip, 
      limit: options.limit, 
     }), 
     new Counter('transactionsCount', Transactions.find(query, { 
      sort: sortbyDate 
     })) 
    ]; 
}); 

以下のようなコードを見ては、今私は、マージコレクションとして希望取引(分別収集)を公開します。「取引」

Meteor.publish('transactions', function(limit){ 
    return Transactions.find(
     { 
      owner: this.userId 
     }); 
}); 

、ここでは最もあるとして別途マージコレクションを公開するこの1つはtransactionsとして名前にsで終わるので、上記1(transaction

と混同しないよう注意してください

挿入 $outで最初にI aggregatedすべての結果第三のコレクション内の2つのコレクションをマージした後、 batchで第2の収集を追加する出版物で呼び出さ重要方法
import { Expenses } from '../../../api/expences/expenses' 
import { Incomes } from '../../../api/incomes/incomes' 
import { Transactions } from '../transactions' 
import Future from 'fibers/future'; 
export const copyTransactions = new ValidatedMethod({ 
    name: 'copyTransactions', 
    validate:null, 
    run() { 
     //we are using future here to make it asynchronous 
     let fu = new Future(); 
     //here Expenses directly copied in new collection name Transactions 
     // TODO: use $rename or $addField in aggregate instead of $project 
     Expenses.aggregate([{ 
      $project: { 
       account : "$account", 
       amount : "$amount", 
       transactionAt : "$spentAt", 
       description : "$description", 
       category : "$category", 
       type: { 
        $literal: 'expense' 
       }, 
       owner : "$owner", 
       createdAt : "$createdAt" 
      } 
     }, { 
      $out: "transactions" 
     } ]); 
     //now append Transactions collection with incomes with batch insert 
     Incomes.aggregate([{ 
      $project: { 
       account : "$account", 
       amount : "$amount", 
       transactionAt : "$receivedAt", 
       type:{ 
        $literal: 'income' 
       }, 
       project : "$project", 
       owner : "$owner", 
       createdAt : "$createdAt" 
      } 
     }], function (err, result) { 
      //if no doc found then just return 
      if(!result.length){ 
       fu.return('completed') 
      } 
      else{ 
       Transactions.batchInsert(result, function(err, res){ 
        fu.return('completed') 
       }) 
      } 

     }); 
     return fu.wait(); 
    } 
}); 

すぎ$outとセカンドコレクションaggregatedが、それは :(

@clientが上書きされた場合、私はちょうど私のオプションとクエリとの「取引」を購読する必要があり、リアルタイムのマージを得ましたTransactions

+0

'$ project'を使用しました。私の現在のバージョンは残念なことに '$ rename'と' $ addField'をサポートしていません –

関連する問題