MongoDB 2.2+のAggregation Frameworkを使用してこの問題を解決する方法はいくつかあります。
残念ながら、2.2.2 の集約フレームワークは$slice
まだ or 配列サブセット演算子をサポートしていないため、追加の操作が必要です。
注: 以下の例ではmongo
シェルを使用していますが、PHP ドライバーに変換するのは簡単です。
例 #1: Aggregation Framework を使用して 2 つの一致 (最初と最後) を抽出する
$first
グループ化ごとにどの 2 つの要素を取得するかを気にしないと仮定すると、 andを選択できます$last
。
db.cars.aggregate(
// Group by $L and find the first and last elements
{ $group: {
_id: '$L',
first: { $first: "$M" },
last: { $last: "$M" },
}},
// Add an extra $index for # of array elements
{ $project: {
first: 1,
last: 1,
index: { $const:[0,1] }
}},
// Split into document stream based on $index
{ $unwind: '$index' },
// Re-group data using conditional to create array
{ $group: {
_id: '$_id',
M: {
$push: { $cond:[ {$eq:['$index', 0]}, '$first', '$last'] }
}
}}
)
出力例:
{
"result" : [
{
"_id" : "cars",
"M" : [
"wolkswagen",
"mercedes"
]
},
{
"_id" : "bike",
"M" : [
"bianchi",
"brook"
]
}
],
"ok" : 1
}
例 #2: Aggregation Framework を使用してセットを作成し、次に削減します
上記の代替手段は$addToSet
、配列要素をトリムするための後処理ステップを使用した単純なパイプラインです。
var agg = db.cars.aggregate(
{ $group: {
_id: '$L',
'M': { $addToSet: "$M" },
}}
)
// Iterate to trim each result to the desired # of elements
agg.result.forEach(function(doc) {
// Note: you could randomly select 2 (or n) elements here
doc.M = doc.M.slice(0,2);
})
出力形式は例 1 と同じですが、最初と最後の要素を選択する代わりに、例 2 (書かれているとおり) は最初の 2 つの要素を選択します。