假设我有一个交易数据表,其形状如下:
{
tokenAddress: string; // Address of token
to: string; // Address of wallet receiving token
from: string; // Address of wallet sending token
quantity: number; // Number of tokens sent
}
我想执行一个聚合,像一样转换这些数据
{
tokenAddress: string; // Address of token
walletAddress: string; // Each wallet has a row
quantity: number; // Number of tokens in wallet
}
我目前正在通过提取平面事务数据并在应用程序代码中执行相当复杂的reduce来完成这项工作。
export const getAddressesTokensTransferred = async (
walletAddresses: string[]
) => {
const collection = await getCollection('tokenTransfers');
const result = await collection
.find({
$or: [
{ from: { $in: walletAddresses } },
{ to: { $in: walletAddresses } },
],
})
.toArray();
return result.reduce((acc, { tokenAddress, quantity, to, from }) => {
const useTo = walletAddresses.includes(to);
const useFrom = walletAddresses.includes(from);
let existingFound = false;
for (const existing of acc) {
if (existing.tokenAddress === tokenAddress) {
if (useTo && existing.walletAddress === to) {
existingFound = true;
existing.quantity += quantity;
break;
} else if (useFrom && existing.walletAddress === from) {
existingFound = true;
existing.quantity -= quantity;
break;
}
}
}
if (!existingFound) {
if (useTo) {
acc.push({ tokenAddress, walletAddress: to, quantity });
}
if (useFrom) {
acc.push({
tokenAddress,
walletAddress: from,
quantity: quantity * -1,
});
}
}
return acc;
}, [] as { tokenAddress: string; walletAddress: string; quantity: number }[]);
};
我觉得在MongoDB中一定有更好的方法来做到这一点,但我只是没有足够的经验来知道如何做到。非常感谢您的帮助!
编辑-添加一些示例文档:
输入墙地址:
[
'0x72caf7c477ccab3f95913b9d8cdf35a1caf25555',
'0x5b6e57baeb62c530cf369853e15ed25d0c82a866'
]
初始find
:的结果
[
{
to: "0x123457baeb62c530cf369853e15ed25d0c82a866",
from: "0x4321f7c477ccab3f95913b9d8cdf35a1caf25555",
quantity: 5,
tokenAddress: "0x12129ec85eebe10a9b01af64e89f9d76d22cea18",
},
{
to: "0x123457baeb62c530cf369853e15ed25d0c82a866",
from: "0x0000000000000000000000000000000000000000",
quantity: 5,
tokenAddress: "0x12129ec85eebe10a9b01af64e89f9d76d22cea18"
},
{
to: "0x4321f7c477ccab3f95913b9d8cdf35a1caf25555",
from: "0x0000000000000000000000000000000000000000",
quantity: 5,
tokenAddress: "0x12129ec85eebe10a9b01af64e89f9d76d22cea18"
},
{
to: "0x4321f7c477ccab3f95913b9d8cdf35a1caf25555",
from: "0x0000000000000000000000000000000000000000",
quantity: 5,
tokenAddress: "0x12129ec85eebe10a9b01af64e89f9d76d22cea18"
}
]
这是一个小样本,只有两个钱包(另一个0x000,以及walletAddresses数组中任何其他而非的钱包基本上都可以丢弃(和一个令牌(可能有很多,我们希望每个钱包都有一行与钱包的交易(
期望的结果是
[
{
tokenAddress: '0x86ba9ec85eebe10a9b01af64e89f9d76d22cea18',
walletAddress: '0x72caf7c477ccab3f95913b9d8cdf35a1caf25555',
quantity: 5
},
{
tokenAddress: '0x86ba9ec85eebe10a9b01af64e89f9d76d22cea18',
walletAddress: '0x5b6e57baeb62c530cf369853e15ed25d0c82a866',
quantity: 10
}
]
一个选项是"重复";事务并根据CCD_ 2临时保存它们。这样我们就可以通过walletAddress
:对它们进行分组
db.collection.aggregate([
{
$project: {
data: [
{walletAddress: "$from",
quantity: {$multiply: ["$quantity", -1]},
tokenAddress: "$tokenAddress"},
{walletAddress: "$to",
quantity: "$quantity",
tokenAddress: "$tokenAddress"}
]
}
},
{$unwind: "$data"},
{$group: {
_id: "$data.walletAddress",
quantity: {$sum: "$data.quantity"},
tokenAddress: {$first: "$data.tokenAddress"}
}},
{$match: {
_id: {$in: [
"0x4321f7c477ccab3f95913b9d8cdf35a1caf25555",
"0x123457baeb62c530cf369853e15ed25d0c82a866"
]
}
}}
])
看看它是如何在操场上工作的例子