背景
DynamoDB に対する CommandInput を、条件によって切り替えたかった。
イメージとしては、以下の FilterExpression を On/Off したかった
Expression
const params = {
ExpressionAttributeNames: {
"#PK": uid,
"#timestamp": "timestamp"
},
ExpressionAttributeValues: {
":PK": userID,
":sortkeyval1": startDate.getTime(),
":sortkeyval2": endDate.getTime()
},
KeyConditionExpression: "#PK = :PK"
FilterExpression: "#timestamp BETWEEN :sortkeyval1 AND :sortkeyval2"
}
結論
スプレッド構文を使って、浅いコピーを利用する
merge する部分が微妙な感じになってしまうけど、まぁ、ライブラリも使わなくて済む
merge
const keyCondition = {
ExpressionAttributeNames: {
"#PK": "uid",
},
ExpressionAttributeValues: {
":PK": userID,
},
KeyConditionExpression: "#PK = :PK",
}
const filterExpression = {
ExpressionAttributeNames: {
"#timestamp": "timestamp"
},
ExpressionAttributeValues: {
":sortkeyval1": startDate.getTime(),
":sortkeyval2": endDate.getTime(),
},
FilterExpression: "#timestamp BETWEEN :sortkeyval1 AND :sortkeyval2"
}
const params = (withFilter)?
{...keyCondition, ...filterExpression, ExpressionAttributeNames: {...keyCondition.ExpressionAttributeNames,
...filterExpression.ExpressionAttributeNames}, ExpressionAttributeValues: {...keyCondition.ExpressionAttributeValues, ...filterExpression.ExpressionAttributeValues}}:
keyCondition;
lodash を使う場合
merge by lodash
import _ from "lodash";
const paramsMerged = (withFilter)?
_.merge(keyCondition, filterExpression):
keyCondition;
結果
どちらも以下になる。分かりやすさとしては lodash でしょうねぇ
merged result
{
ExpressionAttributeNames: {
'#PK': 'uid',
'#timestamp': 'timestamp'
},
ExpressionAttributeValues: {
':PK': 'uid',
':sortkeyval1': 1672148172970,
':sortkeyval2': 1672148172970
},
KeyConditionExpression: '#PK = :PK',
FilterExpression: '#timestamp BETWEEN :sortkeyval1 AND :sortkeyval2'
}
スプレッド構文の試行
スプレッド構文自体の理解の為に、色々試してみた
var content1 = {
id: "1",
timestamp: 123
}
var content2 = {
uid2: "2"
};
var content3 = {
id: "3"
};
var value = "4";
var value2 = "5";
var content4 = {
type: {
audience: "people",
}
};
var content5 = {
type: {
audience: "animal",
author: "person",
batchSize: 5,
},
id: 1,
}
console.log({value, ...content1}, "変数とオブジェクト");
console.log({value, ...content1, value2}, "変数とオブジェクト2");
console.log({nameChanged: value, ...content1}, "変数に名前を付けて");
console.log({...{value}, ...content1, }, "オブジェクトにして");
console.log({...{nameChanged: value}, ...content1, }, "オブジェクトにして名前を付けて");
console.log({...content2, ...content1, }, "オブジェクト同士を");
console.log({...{content2}, ...content1, }, "さらにオブジェクト化");
console.log({...{nameChanged: content2}, ...content1, }, "オブジェクトの名前を付けて");
console.log({...content2, ...content1, ...content3, }, "同一プロパティの上書き id = 1 / 3");
console.log({...content5, ...content4, type: {...content5.type, ...content4.type}}, "プロパティにオブジェクトがある場合");
結果
プロパティ名を変更しながら Merge したい時や、変数を組み込みつつって時に便利そう。
一番最後のが、上の結論に利用したプロパティ単位での浅いコピー(shallow copy)
result
{ value: '4', id: '1', timestamp: 123 } // 変数とオブジェクト
{ value: '4', id: '1', timestamp: 123, value2: '5' } // 変数とオブジェクト2
{ nameChanged: '4', id: '1', timestamp: 123 } // 変数に名前を付けて
{ value: '4', id: '1', timestamp: 123 } // オブジェクトにして
{ nameChanged: '4', id: '1', timestamp: 123 } // オブジェクトにして名前を付けて
{ uid2: '2', id: '1', timestamp: 123 } // オブジェクト同士を
{ content2: { uid2: '2' }, id: '1', timestamp: 123 } // さらにオブジェクト化
{ nameChanged: { uid2: '2' }, id: '1', timestamp: 123 } // オブジェクトの名前を付けて
{ uid2: '2', id: '3', timestamp: 123 } // 同一プロパティの上書き id = 1 / 3
{ type: { audience: 'people', author: 'person', batchSize: 5 }, id: 1 } // プロパティにオブジェクトがある場合
あとがき
スプレッド構文を知らなかったけれど、オブジェクトを結合ってだけで以下に辿り着けて助かりました。感謝