0

以下の形式のデータを持つコレクション内の目的別にグループ化したいと考えています。

[unique_id] => 649083802  
[objectives_compleeted_log_queue] => Array (  
)  
[objectives] => Array (      
        [37] => Array (  
            [is_completed] =>   
            [tasks] => Array (  
            [56] => Array (  
                [completed_count] => 0  
                [actions] => Array (  
                    [0] => 0  
                )  
            )  
        )  
    )  
    [96] => Array (  
        [is_completed] =>   
        [tasks] => Array (   
            [123] => Array (  
                [completed_count] => 0  
                [actions] => Array (  
                    [0] => 0  
                )  
            )  
        )  
    )  
    [97] => Array (  
        [is_completed] =>   
        [tasks] => Array (  
            [124] => Array (  
                [completed_count] => 0  
                [actions] => Array (  
                    [0] => 0  
                )  
            )  
        )  
    )

上記の例では、目的 (37、96、97...) ごとに unique_ids をグループ化する必要があります。申し訳ありませんが、mongo dbは初めてです

4

1 に答える 1

1

経験則として、ドキュメントで動的なフィールド名 (例: objectives.37) を使用すると、インデックス作成とクエリの柔軟性が低下します。まず、マルチキー インデックスを利用することはできません。

それにもかかわらず、 map/reduceを使用して、既存のスキーマ内の個別の ID を集計およびカウントできます。以下の例を簡潔にするために、フィールド名を短くしてo、データ フィクスチャからの無関係なデータにしました。

<?php

$m = new Mongo();
$db = $m->test;

$db->foo->drop();
$db->foo->insert(['o' => [36 => [], 63 => [], 64 => []]]);
$db->foo->insert(['o' => [12 => [], 36 => [], 97 => []]]);

$result = $db->command([
  'mapreduce' => 'foo',
  'map' => new MongoCode('
    function() {
      for (var key in this.o) emit(key, { count: 1 });
    }
  '),
  'reduce' => new MongoCode('
    function(key, values) {
      var r = { count: 0 };
      values.forEach(function(v) { r.count += v.count; });
      return r;
    }
  '),
  'out' => ['inline' => 1]
]);

echo json_encode($result, JSON_PRETTY_PRINT);

ここでは、コレクション全体で map 関数を実行し、o処理するオブジェクト内の一意のキーをそれぞれ発行しています。放出ごとに、放出する初期値は です{count: 1}{count: 1}マッピング後、キーとペアで構成される大量のエミッションが得られます。次に、reduce メソッドを呼び出して、これらの中間結果を個別のキーに対して処理します。引数の各オブジェクトvaluesは同じ構造 (つまり、前に発行したのと同じ値) に従い、同じ構造の単一の縮小値を返すことが期待されます。

このスクリプトは、次の出力を生成します。

$ php mr.php 
{
    "results": [
        {
            "_id": "12",
            "value": {
                "count": 1
            }
        },
        {
            "_id": "36",
            "value": {
                "count": 2
            }
        },
        {
            "_id": "63",
            "value": {
                "count": 1
            }
        },
        {
            "_id": "64",
            "value": {
                "count": 1
            }
        },
        {
            "_id": "97",
            "value": {
                "count": 1
            }
        }
    ],
    "timeMillis": 17,
    "counts": {
        "input": 2,
        "emit": 6,
        "reduce": 1,
        "output": 5
    },
    "ok": 1
}

objectivesネストされたオブジェクトの配列になるようにスキーマを作り直した場合は、MongoDB 2.2+の集約フレームワークを利用して、より少ない労力で同じ結果を計算できます。

<?php

$m = new Mongo();
$db = $m->test;

$db->foo->drop();
$db->foo->insert(['o' => [['id' => 36], ['id' => 63], ['id' => 64]]]);
$db->foo->insert(['o' => [['id' => 12], ['id' => 36], ['id' => 97]]]);

$result = $db->command([
  'aggregate' => 'foo',
  'pipeline' => [
    ['$project' => ['o' => 1]],
    ['$unwind' => '$o'],
    ['$group' => ['_id' => '$o.id', 'count' => ['$sum' => 1]]],
  ],
]);

echo json_encode($result, JSON_PRETTY_PRINT);

ここでは、集計パイプラインを使用して 3 つの操作を順番に実行します。

  • o検索クエリで特定の出力フィールドを選択するのと同様に、スキャンしたドキュメントのフィールドを投影します。
  • o遭遇する各配列をほどきます。パイプラインをドキュメントのストリームと考えると、このステップには 2 つのドキュメントがあり、それぞれoのフィールドに 3 つのネストされたオブジェクトがあります。巻き戻しにより、6 つのドキュメントが次のステップに進み、各o配列フィールドが配列の要素に置き換えられます。
  • この時点で、o.idフィールドをグループ化識別子として使用し、合計を各要素のグループ値として使用して、ストリーム内のすべてのドキュメントをグループ化します。グループ化された要素ごとに、count値フィールドが 1 ずつ増えます。

このスクリプトは次の出力を生成します。

$ php af.php 
{
    "result": [
        {
            "_id": 12,
            "count": 1
        },
        {
            "_id": 63,
            "count": 1
        },
        {
            "_id": 97,
            "count": 1
        },
        {
            "_id": 64,
            "count": 1
        },
        {
            "_id": 36,
            "count": 2
        }
    ],
    "ok": 1
}
于 2012-08-20T20:34:49.287 に答える