概要
Oracleのdual表と同じようにダミーCollectionを作るとAggregationのいろいろなテストが出来る。
ダミーCollectionの作成
データベース名はdummyでCollectionをdualとする
dualのデータを作成する
> use dummy
switched to db dummy
> db.dual.insert({_id:1})
WriteResult({ "nInserted" : 1 })
> db.dual.find()
{ "_id" : 1 }
>
dualを使った例
データが1件で良い場合
$indexOfArrayのテスト
db.getSiblingDB("dummy").dual.aggregate([
{$project:{
idx1:{$indexOfArray:[[1,2,3,4],3]},
idx2:{$indexOfArray:[[1,2,3,4],5]}
}}
])
{ "_id" : 1, "idx1" : 2, "idx2" : -1 }
上記の**$indexOfArray**をフィールド名を使った例にする。
db.getSiblingDB("dummy").dual.aggregate([
{$project:{
array:[1,2,3,4],
idx1: {$literal: 3}
}},
{$project:{
idx1:{$indexOfArray:["$array","$idx1"]},
idx2:{$indexOfArray:["$array",5]}
}}
])
{ "_id" : 1, "idx1" : 2, "idx2" : -1 }
上記での注意点はidx1: {$literal: 3}
をidx1:3
としないことです
データが複数件必要な場合
$groupの例
ここで問題になるのが、dualは1件しかないので**$group**は難しいです。まずは複数のデータ作成するところから考えます。
db.getSiblingDB("dummy").dual.aggregate([
{$project:{
_id: 0,
idx:[0,1,2,3],
data:[[2, -1], [1, 20], [2, 1], [1, 10]]
}},
{$unwind: "$idx"},
{$project:{
key: {$arrayElemAt:[{$arrayElemAt:["$data", "$idx"]}, 0]},
num: {$arrayElemAt:[{$arrayElemAt:["$data", "$idx"]}, 1]}
}}
])
{ "key" : 2, "num" : -1 }
{ "key" : 1, "num" : 20 }
{ "key" : 2, "num" : 1 }
{ "key" : 1, "num" : 10 }
idx
がdata
の添え字を表し、data
がkey
とnum
の配列[[key0,num0],[key1,num1],...]
になっています。その後の$unwind
で複数ドキュメントを作成して$project
で整形します。
このデータを使って$group
を実行します。
db.getSiblingDB("dummy").dual.aggregate([
{$project:{
_id: 0,
idx:[0,1,2,3],
data:[[2, -1], [1, 20], [2, 1], [1, 10]]
}},
{$unwind: "$idx"},
{$project:{
key: {$arrayElemAt:[{$arrayElemAt:["$data", "$idx"]}, 0]},
num: {$arrayElemAt:[{$arrayElemAt:["$data", "$idx"]}, 1]}
}},
{$group:{
_id:"$key", sum:{$sum:"$num"}
}}
])
{ "_id" : 2, "sum" : 0 }
{ "_id" : 1, "sum" : 30 }
NumberDecimalの四則演算に活用
mongo shellでNumberDecimalの演算方法が見つかりませんでしたので自分で作ってみます。例は加算(add
)のみ記載します。以下を.mongorc.js
に記述します。
NumberDecimal.prototype.add = function(other) {
let result = db.getSiblingDB("dummy").dual.aggregate([
{$project:{
result:{$add:[this, other]}, _id: 0
}}
]).toArray()
return result[0].result
}
演算例
> num=NumberDecimal("123456789012345678901234567890")
NumberDecimal("123456789012345678901234567890")
> num.add(NumberDecimal("1"))
NumberDecimal("123456789012345678901234567891")
終わりに
死活の確認のためにping
コマンドの代わりにdual
をfind
で対応することも可能です。用途はほぼOracle同様の使い方と同じです。
問題があるとすれば、$lookup
や$graphLookup
には使えないことです。これらは複数のドキュメントを持っているCollectionが必要になります。別途dual
以外のCollectionを作れば対応可能です。