简体   繁体   中英

MongoDB Aggregate Array of Objects

I have many documents called 'Item' in the following form:

Item = {
    "_id" : ObjectId("6059f025fb8378a294180cc3"),
    "name" : "My Name",
    "category" : "My Category",
    "marketData" : {
        "currency" : "€",
        "history" : [
            {
                "timestamp" : 1,
                "price" : 1.1,
                "volume" : 10
            },
            {
                "timestamp" : 3,
                "price" : 2.2,
                "volume" : 20
            },
        ]
    }
}

The history has a different length and each document has different timestamps, some documents will share a few timestamps.

I need the sum of prices and volume for each timestamp of each category. Like this:

Categories =
[{
    "_id",
    "name": "My Category",
    "marketData": {
        "currency": "€",
        "history": [
            {
                "timestamp": 1,
                "price": "sum of prices of all items at timestamp 1",
                "volume": "sum of volume of all items at timestamp 1"
            },
            ...
        ]
    }
},
...
]

I have already tried this but it said SyntaxError: invalid property id

db.items.aggregate([
    { $unwind: "$marketData.history" }, 
    {
        $group: {
            _id: "$marketData.history.timestamp", 
            price: { $sum:"$marketData.history.price" }
        },
        {
            $group: {
                _id:null,
                price: { 
                    $push: { timestamp: "$timestamp", price:"$price" }
                }
            }
        },
        {
            $project: {
                marketData.history:1,
                _id:0
            }
        } 
    }
])

SOLUTION 1 : If you just want to group your data.

db.items.aggregate([
    { $unwind: "$marketData.history" },
    {
        $group: {
            _id: {
                category: "$category",
                timestamp: "$marketData.history.timestamp"
            },
            price: { $sum: "$marketData.history.price" },
            volume: { $sum: "$marketData.history.volume" }
        }
    },
    {
        $project: {
            _id: 0,
            category: "$_id.category",
            timestamp: "$_id.timestamp",
            price: "$price",
            volume: "$volume"
        }
    },
    {
        $group: {
            _id: null,
            result: { $push: "$$ROOT" }
        }
    }
]);

SOLUTION 2 : To exactly match your expected output.

db.items.aggregate([
    { $unwind: "$marketData.history" },
    {
        $group: {
            _id: {
                category: "$category",
                timestamp: "$marketData.history.timestamp"
            },
            name: { $first: "$name" },
            currency: { $first: "$marketData.currency" },
            price: { $sum: "$marketData.history.price" },
            volume: { $sum: "$marketData.history.volume" }
        }
    },
    {
        $sort: { "_id.timestamp": 1 }
    },
    {
        $group: {
            _id: "$_id.category",
            category: { $first: "$_id.category" },
            name: { $first: "$name" },
            currency: { $first: "$currency" },
            history: {
                $push: {
                    timestamp: "$_id.timestamp",
                    price: "$price",
                    volume: "$volume"
                }
            }
        }
    },
    {
        $addFields: {
            marketData: {
                currency: "$currency",
                history: "$history"
            },
            currency: "$$REMOVE",
            history: "$$REMOVE"
        }
    }
]);

Output:

/* 1 */
{
    "_id" : "My Category",
    "category" : "My Category",
    "name" : "My Name",
    "marketData" : {
        "currency" : "€",
        "history" : [
            {
                "timestamp" : 1,
                "price" : 10,
                "volume" : 20
            },
            {
                "timestamp" : 3,
                "price" : 2.2,
                "volume" : 20
            }
        ]
    }
},

/* 2 */
{
    "_id" : "My Category 2",
    "category" : "My Category 2",
    "name" : "My Name 2",
    "marketData" : {
        "currency" : "€",
        "history" : [
            {
                "timestamp" : 1,
                "price" : 1.1,
                "volume" : 10
            },
            {
                "timestamp" : 3,
                "price" : 2.2,
                "volume" : 20
            }
        ]
    }
}

Also you are getting that error because there is an extra closing } brace and marketData.history is not enclosed as "marketData.history" . Check the corrected query below:

db.items.aggregate([
    { $unwind: "$marketData.history" },
    {
        $group: {
            _id: "$marketData.history.timestamp",
            price: { $sum: "$marketData.history.price" }
        }
    },
    {
        $group: {
            _id: null,
            price: {
                $push: { timestamp: "$_id", price: "$price" }
            }
        }
    },
    {
        $project: { _id: 0 }
    }
])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM