MongoTemplateの主な利用方法

MongoTemplateの公式ドキュメント:

https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.aggregation.supported-aggregation-operations

1. 登録・削除・更新・検索操作

ネイティブMongoDB:

Queryオブジェクト

  1. Queryオブジェクトを作成(すべての条件を格納する)、その後Criteriaオブジェクトを作成(条件を構築する)

  2. 精確な条件:criteria.and("key").is("値") フレーズ条件:criteria.and("key").regex("値")

  3. 条件をまとめる:query.addCriteria(criteria)

  4. 大きさ比較(新しいCriteriaを作成):Criteria gt = Criteria.where("key").gt("値") 小ささ比較(新しいCriteriaを作成):Criteria lt = Criteria.where("key").lt("値") 5. Query.addCriteria(new Criteria().andOperator(gt,lt));

  5. 1つのQueryには1つのandOperator()のみ使用可能。その引数はCriteria配列でも可。

  6. ソート:query.with(new Sort(Sort.Direction.ASC, "age").and(new Sort(Sort.Direction.DESC, "date")))

2. MongoTemplateによるグループ化・ソート・複雑な操作

**グループ化手法** **理解の難しさ** **パフォーマンス比較** **推奨度**
mongoTemplate.group(); 比較的シンプル 70万件データで2分30秒 SpringBoot環境では非推奨
mongoTemplate.aggregation(); 理解後は非常に便利 同じ環境で10秒未満 推奨

1、mongoTemplate.group(); グループ化可能だがソート不可、非推奨

        // 絞り込み条件の設定
        Criteria criteria = new Criteria();
        criteria.andOperator(
                // getMsgTimeがstartTimeより大きくendTimeより小さいデータを抽出
                Criteria.where("getMsgTime").gte(startTime),
                Criteria.where("getMsgTime").lte(endTime));
        // MongoDBの"deviceCode"でグループ化、デフォルトでグループ化フィールドを保持
        GroupBy groupBy = GroupBy.key("deviceCode")
                // 追加のフィールドを初期化して保持
                .initialDocument("{ count: 0 , onlineCount: 0 , lastTime: 0}")
                // グループ化後のデータに対して計算を行う。docは現在の文書、prevは結果文書。func内ではJavaScript構文を使用可能
                .reduceFunction("function(doc, prev) { prev.count++ ; if(doc.ctlStatus == 1){prev.onlineCount += 1 ;prev.lastTime = doc.getMsgTime ; }}");
        // criteria:絞り込み条件、CTL_HEART_BEAT:コレクション名、DeviceGroupByResult.class:結果オブジェクト
        GroupByResults<DeviceGroupByResult> results = mongoTemplate.group(criteria, "CTL_HEART_BEAT", groupBy, DeviceGroupByResult.class);

        /** 結果を受け取るオブジェクトは、保持するフィールドをオブジェクトにまとめ、getter/setterを追加する
         * DeviceGroupByResult.classにはdeviceCode、count、onlineCount、lastTimeなどのプロパティが含まれている。
         */
        // 結果セットを処理する。iteratorオブジェクトのみ取得可能。リストのように扱うのは困難
        Iterator<DeviceGroupByResult> iterator = results.iterator();
        while (iterator.hasNext()) {
            // ソースコードを見ると、result.iteratorは結果セットを返すが、イテレータでのみ読み取り可能
            DeviceGroupByResult deviceGroupByResult = iterator.next();
        }

2、mongoTemplate.aggregation(); グループ化とソート、推奨される方法

        // 絞り込み条件の設定
        Criteria criteria = new Criteria();
        criteria.andOperator(
                // getMsgTimeがstartTimeより大きくendTimeより小さいデータを抽出
                Criteria.where("getMsgTime").gte(startTime),
                Criteria.where("getMsgTime").lte(endTime));
        // MongoDBのdevice_codeでグループ化
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),// 絞り込み条件を追加
                Aggregation.group("deviceCode").first("deviceCode").as("deviceCode") // deviceCodeでグループ化し、フィールドを保持
                        .last("getMsgTime").as("lastTime")// 最終時間を保持
                        .count().as("count")// カウント
                        // ctlStatusは文字列としてMongoDBに保存されているため、合計を計算するにはListに格納する必要がある
                        .push("ctlStatus").as("currentCtlStatusList")
                        .push("getMsgTime").as("cuurentCtlGetTimeList")// なぜかgetMsgTimeもpushしているのは、ctlstatus==1のときの時刻を取得するため
                // ソートはグループ化の後に指定するため、lastTimeのみ指定可能。グループ化前に指定する場合はgetMsgTimeなどのデータベースフィールドが必要
                // sortは70万件のデータではパフォーマンスが悪く、エラーが発生する可能性がある
                Aggregation.sort(Sort.by(Sort.Order.asc("lastTime")))
        );

        // aggregation:すべての条件を含む、CTL_HEART_BEAT:コレクション名、DeviceGroupByResult.class:結果オブジェクト
        AggregationResults<DeviceGroupByResult> deviceGroupByResults = mongoTemplate.aggregate(aggregation, "CTL_HEART_BEAT", DeviceGroupByResult.class);
        // この方法は非常に使いやすく
        List<DeviceGroupByResult> list = deviceGroupByResults.getMappedResults();

3、ループによる検索(複数回の操作が必要な場合)

        Criteria criteria = new Criteria();
        // timeFrames:時間のリスト
        for (String time : timeFrames) {
            // aggregationに絞り込み条件を設定
            Aggregation aggregation = Aggregation.newAggregation(
                    // 新しいCriteria条件を追加する必要があることに注意
                    // 通常のロジックでは外側のラッパーは不要だが、こうした場合
                    // 第1回目は問題なし、第2回目以降は複数回の絞り込みエラーが発生するため、暗黙的なパラメータ渡しを行う
                    Aggregation.match(new Criteria().andOperator(criteria.where("STATISTICS_YEAR").is(time), criteria)),
                    Aggregation.group("STATISTICS_TIME").first("STATISTICS_TIME").as("time").sum("CAR_FLOW").as("count"),
                    Aggregation.sort(Sort.by(Sort.Order.asc("time")))
            );
            AggregationResults<CarFlowResultVO> carFlowResultVOs = mongoTemplate.aggregate(aggregation, tableName, CarFlowResultVO.class);
            carFlowResultVOList = carFlowResultVOs.getMappedResults();
            carFlowResultVOMap.put(String.valueOf(count), carFlowResultVOList);
            carFlowResultVOList = new ArrayList<>();
            count++;
        }

転載:https://www.cnblogs.com/tiankx/p/13957842.html

タグ: MongoTemplate MongoDB Java SpringData Aggregation

7月26日 19:40 投稿