Spring Data MongoDB - Aggregation Operation - 02

 

UnwindOperation

Document내 array field의 각각의 요소들을 풀어 Document로 변경해주는 MongoDB의 $unwind를 지원해준다.

{ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] }
/*
	db.inventory.aggregate(
		[ { $unwind : "$sizes" } ]
	)
*/
@Test
public void size를_Document로_풀기() {
	UnwindOperation unwindOperation = Aggregation.unwind("sizes");

	Aggregation aggregation = Aggregation.newAggregation(
		unwindOperation
	);

	mongoTemplate.aggregate(aggregation, "inventory", Inventory.class);
}

/* Results
{ "_id" : 1, "item" : "ABC1", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }
*/

 

SampleOperation

샘플링을 지원해주는 MongoDB의 $sample을 지원해준다.

{ "_id" : 1, "name" : "dave123", "q1" : true, "q2" : true }
{ "_id" : 2, "name" : "dave2", "q1" : false, "q2" : false  }
{ "_id" : 3, "name" : "ahn", "q1" : true, "q2" : true  }
{ "_id" : 4, "name" : "li", "q1" : true, "q2" : false  }
{ "_id" : 5, "name" : "annT", "q1" : false, "q2" : true  }
{ "_id" : 6, "name" : "li", "q1" : true, "q2" : true  }
{ "_id" : 7, "name" : "ty", "q1" : false, "q2" : true  }
/*
	db.users.aggregate(
   		[ { $sample: { size: 3 } } ]
	)
*/
@Test
public void 최대_3개로_샘플링() {
	SampleOperation sampleOperation = Aggregation.sample(3L);

	Aggregation aggregation = Aggregation.newAggregation(
		sampleOperation
	);

	mongoTemplate.aggregate(aggregation, "users", User.class);
}

/* Results (Random하게 sampling하여 Results가 다를 수 있음)
{ "_id" : 2, "name" : "dave2", "q1" : false, "q2" : false  }
{ "_id" : 4, "name" : "li", "q1" : true, "q2" : false  }
{ "_id" : 7, "name" : "ty", "q1" : false, "q2" : true  }
*/

 

GroupOperation

특정 field를 기준으로 그룹화하는 MongoDB의 $group을 지원해준다.

{ "_id" : 1, "item" : "abc", "price" : NumberDecimal("10"), "quantity" : NumberInt("2"), "date" : ISODate("2014-03-01T08:00:00Z") }
{ "_id" : 2, "item" : "jkl", "price" : NumberDecimal("20"), "quantity" : NumberInt("1"), "date" : ISODate("2014-03-01T09:00:00Z") }
{ "_id" : 3, "item" : "xyz", "price" : NumberDecimal("5"), "quantity" : NumberInt( "10"), "date" : ISODate("2014-03-15T09:00:00Z") }
{ "_id" : 4, "item" : "xyz", "price" : NumberDecimal("5"), "quantity" :  NumberInt("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") }
{ "_id" : 5, "item" : "abc", "price" : NumberDecimal("10"), "quantity" : NumberInt("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") }
{ "_id" : 6, "item" : "def", "price" : NumberDecimal("7.5"), "quantity": NumberInt("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") }
{ "_id" : 7, "item" : "def", "price" : NumberDecimal("7.5"), "quantity": NumberInt("10") , "date" : ISODate("2015-09-10T08:43:00Z") }
{ "_id" : 8, "item" : "abc", "price" : NumberDecimal("10"), "quantity" : NumberInt("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") }
/*
	db.sales.aggregate( [
		{ $group : { _id : "$item", totalSum: { $sum: "$price" } } }
	] )
*/
@Test
public void item으로_그룹화한_가격_총합() {
	GroupOperation groupOperation = Aggregation.group("item")
		.sum("price").as("totalSum");

	Aggregation aggregation = Aggregation.newAggregation(
		groupOperation
	);

	mongoTemplate.aggregate(aggregation, "sales", Sale.class);
}

/*
{ "_id" : "abc", "totalSum" : 30 }
{ "_id" : "jkl", "totalSum" : 20 }
{ "_id" : "def", "totalSum" : 15 }
{ "_id" : "xyz", "totalSum" : 10 }
*/

 

LookupOperation

Left Outer Join과 같이 콜렉션과 Join하는 MongoDB의 $lookup을 지원해준다.

// `orders` collection
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 },
{ "_id" : 3  }

// `inventory` collection
{ "_id" : 1, "sku" : "almonds", "description": "product 1", "instock" : 120 },
{ "_id" : 2, "sku" : "bread", "description": "product 2", "instock" : 80 },
{ "_id" : 3, "sku" : "cashews", "description": "product 3", "instock" : 60 },
{ "_id" : 4, "sku" : "pecans", "description": "product 4", "instock" : 70 },
{ "_id" : 5, "sku": null, "description": "Incomplete" },
{ "_id" : 6 }
/*
    db.orders.aggregate([
      {
         $lookup:
           {
             from: "inventory",
             localField: "item",
             foreignField: "sku",
             as: "inventory_docs"
           }
      }
    ])
*/
@Test
public void 각_주문의_재고정보() {
	LookupOperation lookupOperation = Aggregation.lookup("inventory", "item", "sku", "inventory_docs");

	Aggregation aggregation = Aggregation.newAggregation(
		lookupOperation
	);

	mongoTemplate.aggregate(aggregation, "orders", Order.class);
}

/*
{
   "_id" : 1,
   "item" : "almonds",
   "price" : 12,
   "quantity" : 2,
   "inventory_docs" : [
      { "_id" : 1, "sku" : "almonds", "description" : "product 1", "instock" : 120 }
   ]
}
{
   "_id" : 2,
   "item" : "pecans",
   "price" : 20,
   "quantity" : 1,
   "inventory_docs" : [
      { "_id" : 4, "sku" : "pecans", "description" : "product 4", "instock" : 70 }
   ]
}
{
   "_id" : 3,
   "inventory_docs" : [
      { "_id" : 5, "sku" : null, "description" : "Incomplete" },
      { "_id" : 6 }
   ]
}
*/

 

CountOperation

Document들의 개수를 나타내주는 MongoDB의 $count를 지원해준다.

{ "_id" : 1, "subject" : "History", "score" : 88 }
{ "_id" : 2, "subject" : "History", "score" : 92 }
{ "_id" : 3, "subject" : "History", "score" : 97 }
{ "_id" : 4, "subject" : "History", "score" : 71 }
{ "_id" : 5, "subject" : "History", "score" : 79 }
{ "_id" : 6, "subject" : "History", "score" : 83 }
/*
  db.scores.aggregate(
    [
      {
        $match: {
          score: {
            $gt: 80
          }
        }
      },
      {
        $count: "passing_scores"
      }
    ]
  )
*/
@Test
public void 점수가_80초과인_총_개수() {
	MatchOperation matchOperation = Aggregation.match(Criteria.where("score").gt(80));

	CountOperation countOperation = Aggregation.count().as("passing_scores");

	Aggregation aggregation = Aggregation.newAggregation(
		matchOperation,
		countOperation
	);

	mongoTemplate.aggregate(aggregation, "scores", Score.class);
}

Leave a comment