Java=でMongoを使用しているのは初めてで、この集約クエリで問題が発生しています。リポジトリの@Query
アノテーションを使用して、Mongo for Springでいくつかの簡単なクエリを実行できますMongoRepository<T, ID>
を拡張するインターフェースです。Spring-Dataで長い集計を行う場合、どのアプローチを取るかを知っておくと役に立ちます。
db.post.aggregate([
{
$match: {}
},
{
$lookup: {
from: "users",
localField: "postedBy",
foreignField: "_id",
as: "user"
}
},
{
$group: {
_id: {
username: "$user.name",
title: "$title",
description: "$description",
upvotes: { $size: "$upvotesBy" },
upvotesBy: "$upvotesBy",
isUpvoted: { $in: [req.query.userId, "$upvotesBy"] },
isPinned: {
$cond: {
if: { $gte: [{ $size: "$upvotesBy" }, 3] },
then: true,
else: false
}
},
file: "$file",
createdAt: {
$dateToString: {
format: "%H:%M %d-%m-%Y",
timezone: "+01",
date: "$createdAt"
}
},
id: "$_id"
}
}
},
{ $sort: { "_id.isPinned": -1, "_id.createdAt": -1 } }
])
AggregationOperation を実装し、カスタムの集計操作クエリを記述してから、MongoTemplate
を使用して、mongo Shellで実行したmongo Shellクエリを次のように実行できます。
カスタム集計操作
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
public class CustomAggregationOperation implements AggregationOperation {
private String jsonOperation;
public CustomAggregationOperation(String jsonOperation) {
this.jsonOperation = jsonOperation;
}
@Override
public org.bson.Document toDocument(AggregationOperationContext aggregationOperationContext) {
return aggregationOperationContext.getMappedObject(org.bson.Document.parse(jsonOperation));
}
}
任意のMongo Shell Aggregationクエリエグゼキュータ
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.stereotype.Service;
import sample.data.mongo.models.Course;
@Service
public class LookupAggregation {
@Autowired
MongoTemplate mongoTemplate;
public void LookupAggregationExample() {
AggregationOperation unwind = Aggregation.unwind("studentIds");
String query1 = "{$lookup: {from: 'student', let: { stuId: { $toObjectId: '$studentIds' } },"
+ "pipeline: [{$match: {$expr: { $eq: [ '$_id', '$$stuId' ] },},}, "
+ "{$project: {isSendTemplate: 1,openId: 1,stu_name: '$name',stu_id: '$_id',},},], "
+ "as: 'student',}, }";
TypedAggregation<Course> aggregation = Aggregation.newAggregation(
Course.class,
unwind,
new CustomAggregationOperation(query1)
);
AggregationResults<Course> results =
mongoTemplate.aggregate(aggregation, Course.class);
System.out.println(results.getMappedResults());
}
}
詳細については、 Githubリポジトリ クラスを見てください:CustomAggregationOperation&LookupAggregation
他のアプローチも使用していますMongoTemplate:
#1。モデルのカスタムコードのインターフェイスを定義しますPost:
interface CustomPostRepository {
List<Post> yourCustomMethod();
}
#2。このクラスの実装を追加し、命名規則に従ってクラスを見つけられるようにします。
class CustomPostRepositoryImpl implements CustomPostRepository {
@Autowired
private MongoOperations mongoOperations;
public List<Post> yourCustomMethod() {
// custom match queries here
MatchOperation match = null;
// Group by , Lookup others stuff goes here
// For details: https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/aggregation/Aggregation.html
Aggregation aggregate = Aggregation.newAggregation(match);
AggregationResults<Post> orderAggregate = mongoOperations.aggregate(aggregate,
Post.class, Post.class);
return orderAggregate.getMappedResults();
}
}
#3。次に、ベースリポジトリインターフェースでカスタムインターフェースを拡張すると、インフラストラクチャがカスタム実装を自動的に使用します。
interface PostRepository extends CrudRepository<Post, Long>, CustomPostRepository {
}
これは古いスレッドですが、MongoRepositoryでこのスレッドを見つけた人なら誰でも安全にマルチステージ/パイプライン集約(何と呼ばれるかわからない)を実行できるようになることを願っています。 mongoテンプレートなしのmongoリポジトリで手掛かりと集約の例を探すのにも苦労しているので。
しかし、今、春のドキュメント here で述べられているように、アグリゲーションパイプラインを実行できます
Mongoshellでは、私の集計は次のようになります。
db.getCollection('SalesPo').aggregate([
{$project: {
month: {$month: '$poDate'},
year: {$year: '$poDate'},
amount: 1,
poDate: 1
}},
{$match: {$and : [{year:2020} , {month:7}]
}}
,
{$group: {
'_id': {
month: {$month: '$poDate'},
year: {$year: '$poDate'}
},
totalPrice: {$sum: {$toDecimal:'$amount'}},
}
},
{$project: {
_id: 0,
totalPrice: {$toString: '$totalPrice'}
}}
])
MongoRepositoryで@Aggregationアノテーションに変換している間、以下のようになります(アポストレーフィを削除し、メソッドparamsで置き換えます)。
@Repository
public interface SalesPoRepository extends MongoRepository<SalesPo, String> {
@Aggregation(pipeline = {"{$project: {\n" +
" month: {$month: $poDate},\n" +
" year: {$year: $poDate},\n" +
" amount: 1,\n" +
" poDate: 1\n" +
" }}"
,"{$match: {$and : [{year:?0} , {month:?1}] \n" +
" }}"
,"{$group: { \n" +
" '_id': {\n" +
" month: {$month: $poDate},\n" +
" year: {$year: $poDate} \n" +
" },\n" +
" totalPrice: {$sum: {$toDecimal:$amount}},\n" +
" }\n" +
" }"
,"{$project: {\n" +
" _id: 0,\n" +
" totalPrice: {$toString: $totalPrice}\n" +
" }}"})
AggregationResults<SumPrice> sumPriceThisYearMonth(Integer year, Integer month);
私のドキュメントは次のようになります:
@Document(collection = "SalesPo")
@Data
public class SalesPo {
@Id
private String id;
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate poDate;
private BigDecimal amount;
}
そして、予測を保持するためのSumPriceクラス:
@Data
public Class SumPrice {
private BigDecimal totalPrice;
}
この答えが、mongotemplateを使用せずにmongorepositoryで集約を試みる人を助けることができることを願っています。