MongoDB Unwind Error: cannot encode object of type: <class 'set'> - mongodb

hope you're fine.
I cannot seem to find a way to aggregate the following document by 'equity id'.
{
"_id": {
"$oid": "6001dc246192c700013e8252"
},
"user": "blablabla",
"_type": "User::Individual",
"created_at": {
"$date": "2021-01-15T18:17:11.130Z"
},
"integrations": [{
"_id": {
"$oid": "6001dc62e7a0970001258da8"
},
"status": "completed",
"authentication_failed_msg": null
}],
"portfolios": [{
"_id": {
"$oid": "6001dc62e7a0970001258da9"
},
"_type": "SimplePortfolio",
"transactions": [{
"_id": {
"$oid": "6001dc62e7a0970001258daa"
},
"settlement_period": 2,
"expenses": 0,
"source": "integration",
"_type": "Transaction::Equity::Buy",
"date": {
"$date": "2020-03-02T00:00:00.000Z"
},
"shares": 100,
"price": 13.04,
"equity_id": "abcd"
}, {
"_id": {
"$oid": "6001dc62e7a0970001258dab"
},
"settlement_period": 2,
"expenses": 0,
"source": "integration",
"_type": "Transaction::Equity::Buy",
"date": {
"$date": "2020-03-02T00:00:00.000Z"
},
"shares": 1000,
"price": 1.03,
"equity_id": "efgh"
I tried something like
db.collection.aggregate([{"$unwind": {'$portfolios.transactions'}},
{"$group" : {"_id": "$equity_id"}}])
Got error InvalidDocument: cannot encode object: {'$portfolios.transactions'}, of type: <class 'set'>
Ideally what I want a list grouped by user and equity_id and a sum of its shares. Does anyone know if the error is caused by my aggregation or the document structure?

You should $unwind twice.
db.collection.aggregate([
{
"$unwind": "$portfolios"
},
{
"$unwind": "$portfolios.transactions"
},
{
"$group": {
"_id": "$portfolios.transactions.equity_id"
}
}
])
mongoplayground

Related

Aggregate occurrences of events in nested array

Given the following input:
[
{
"statuses": [
{
"status": "allowed",
"count": 3,
"events_count": [
"2001",
"1001",
"1001"
]
}
],
"date": "2022-09-10 15:00",
"_id": "2022-09-10 15:00"
}
]
I need count the number of occurrences of stauses.events_count, so the output would be:
[
{
"statuses": [
{
"status": "allowed",
"count": 3,
"events_count": [
{"type": "2001", "count": 1},
{"type": "1001", "count": 2},
]
}
],
"date": "2022-09-10 15:00",
"_id": "2022-09-10 15:00"
}
]
What I've tried
This is what I got so far:
db.collection.aggregate([
{
"$unwind": "$statuses"
},
{
"$unwind": "$statuses.events_count"
},
{
"$group": {
"_id": {
"event_count": "$statuses.events_count",
"status": "$statuses.status",
"date": "$date",
"count": "$statuses.count"
},
"occurences": {
"$sum": 1
}
}
}
])
Which produces:
[
{
"_id": {
"count": 3,
"date": "2022-09-10 15:00",
"event_count": "2001",
"status": "allowed"
},
"occurences": 1
},
{
"_id": {
"count": 3,
"date": "2022-09-10 15:00",
"event_count": "1001",
"status": "allowed"
},
"occurences": 2
}
]
I'm having difficulties grouping everything back together. I tried grouping by date and pushing back to a 'statuses' array, but it produces two items in the array (with status==allowed), rather than 1 item with status==allowed
You did 2 $unwinds, so it should be 2 $groups in reverse order:
{
"$group": {
"_id": {
"status": "$_id.status",
"count": "$_id.count",
"date": "$_id.date"
},
"event_count": {
"$push": {
"type": "$_id.event_count",
"count": "$occurences"
}
}
}
},
{
"$group": {
"_id": "$_id.date",
"date": {"$last": "$_id.date"},
"statuses": {
"$push": {
"status": "$_id.status",
"count": "$_id.count",
"event_count": "$event_count"
}
}
}
}

MongoDB count,min,max,avg for aggregate using field with List of objects

I have problem with get statistics data using MongoDB collection.
Collection
[
{
"_id": {"$oid": "616309f71b021c754992bfca"},
"correlatedNodes": [
{
"type": "IS_ULTIMATELY_CONSOLIDATED_BY",
"nodes": ["I07WOS4YJ0N7YRFE7309"]
}
],
"fromTaskId": 20,
"nodeName": "5493000U0YGG4VEQOX65"
},
{
"_id": {"$oid": "616309f71b021c754992bfcb"},
"correlatedNodes": [
{
"type": "IS_DIRECTLY_CONSOLIDATED_BY",
"nodes": ["529900P6OUCFPVWCFE19", "8945007IZBKFQUQLIP85"]
},
{
"type": "IS_ULTIMATELY_CONSOLIDATED_BY",
"nodes": ["529900P6OUCFPVWCFE19"]
}
],
"fromTaskId": 20,
"nodeName": "89450012XZ2GPWGIGH37"
},
{
"_id": {"$oid": "616309f71b021c754992bfcc"},
"correlatedNodes": [
{
"type": "IS_ULTIMATELY_CONSOLIDATED_BY",
"nodes": ["815600C9588783AB0210"]
},
{
"type": "IS_DIRECTLY_CONSOLIDATED_BY",
"nodes": ["815600C9588783AB0210"]
}
],
"fromTaskId": 20,
"nodeName": "815600228127946DFF05"
},
{
"_id": {"$oid": "616309f71b021c754992bfcd"},
"correlatedNodes": [
{
"type": "IS_ULTIMATELY_CONSOLIDATED_BY",
"nodes": ["549300LI58A0MHGHTZ98"]
}
],
"fromTaskId": 20,
"nodeName": "549300NV4OCF16TAS048"
}
]
I want to get basic statistic information for correlatedNodes field.
Something like:
{
"IS_ULTIMATELY_CONSOLIDATED_BY": {
"count": 567,
"avg": 22,
"min": 3,
"max": 50
}
}
By count I mean to use list size for each connection type.
I tried aggregate query like this:
db.node_correlations.aggregate([
{
$project: {"correlatedNodes": "$correlatedNodes" },
$unwind: "$correlatedNodes"
}
]);
But I received error:
[2021-10-13 12:14:10] com.mongodb.MongoCommandException: Command failed with error 40323 (Location40323): 'A pipeline stage specification object must contain exactly one field.' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "A pipeline stage specification object must contain exactly one field.", "code": 40323, "codeName": "Location40323"}
Thank you everyone for help.
Working solutions is:
db.node_correlations.aggregate([
{
"$unwind": "$correlatedNodes"
},
{
"$group": {
"_id": "$correlatedNodes.type",
"count": {
"$sum": {"$size": "$correlatedNodes.nodes"}
},
"avg": {
"$avg": {"$size": "$correlatedNodes.nodes"}
},
"min": {
"$min": {"$size": "$correlatedNodes.nodes"}
},
"max": {
"$max": {"$size": "$correlatedNodes.nodes"}
}
}
}
])

MongoDB Ignoring duplicate documents using unique key in aggregate

Documents looks like this.
{
"sId": "s1",
"language": "hindi",
"service": "editing",
"count": 5,
},
{
"sId": "s2",
"language": "hindi",
"service": "editing",
"count": 6,
},
{
"sId": "s2",
"language": "hindi",
"service": "reading",
"count": 6,
},
{
"sId": "s3",
"language": "english",
"service": "reading",
"count": 10,
}
I want the result should be like this
{
"language":"hindi",
"count": 11
},
{
"language":"english",
"count": 10
}
I tried with the aggregate query like this
{
"$group": {
"_id": {
"lang": "$language",
"sId": "$sId"
},
"count": {"$sum": "$count"}
}
}
In sId: s2 it should ignore the second object.
Can anyone please give me a hint how I can achieve the above.
You can use $first to get the first element of each group. You can then use $group again to sum by language.
{
"$group": {
"_id": {
"language": "$language",
"sId": "$sId"
},
"count": {
"$first": {
"$sum": "$count"
}
}
}
}
https://mongoplayground.net/p/3_RjSt1wtRS

Mongo Aggs and total count

I experiencing some trouble in mongodb to do a query on collection to get all documents filtered, paginate(with skip and limit) and get the total count like that
The chat document look like that:
{
"_id": "c603db3e75ec76f5a4dff559bc525e29",
"members": [{
"user": "5b2b0d5135cfd60185034bf6",
"status": "creator"
}, {
"user": "5b31dc3f88284a009fa847e5",
"status": "member"
}],
"messages": [{
"_id": 2,
"from": "5b2b0d5135cfd60185034bf6",
"parse_mode": "none",
"text": "fffasdfsa",
"attachment": null,
"time": 1529995684119,
"type": "text"
},
{...},
{...}
]}
And i would like to get result like that
{
total_count: 3,
chats: [{
"_id": "c603db3e75ec76f5a4dff559bc525e29",
"members": [{
"user": "5b2b0d5135cfd60185034bf6",
"status": "creator"
}, {
"user": "5b31dc3f88284a009fa847e5",
"status": "member"
}],
"creator": {
"user": "5b2b0d5135cfd60185034bf6",
"status": "creator"
},
"lastMessage": {
"_id": 4,
"from": "5b2b0d5135cfd60185034bf6",
"parse_mode": "none",
"text": "aasdas",
"attachment": null,
"time": 1529995698736,
"type": "text"
},
"messages": [{
"_id": 2,
"from": "5b2b0d5135cfd60185034bf6",
"parse_mode": "none",
"text": "fffasdfsa",
"attachment": null,
"time": 1529995684119,
"type": "text"
}, {
"_id": 3,
"from": "5b2b0d5135cfd60185034bf6",
"parse_mode": "none",
"text": "weqw",
"attachment": null,
"time": 1529995690015,
"type": "text"
}, {
"_id": 4,
"from": "5b2b0d5135cfd60185034bf6",
"parse_mode": "none",
"text": "aasdas",
"attachment": null,
"time": 1529995698736,
"type": "text"
}]
},
{...},
{...}
]
}
My query is
collection<DbChat>('chats').aggregate([
{
$match: {
messages: { $exists: true }
}
},
{ $unwind: '$messages' },
{ $unwind: '$members' },
{ $group: {_id: '$_id', members: { $push: '$members' }, member: { $last: '$members' }, creator: { $first: '$members' }, messages: {$push: '$messages' } , lastMessage: {$last: '$messages'}}},
{ $sort: this.sort},
]}.skip(skip).limit(size)
with this query i dont get the total_count I tried lot of things but i didnt found a way to get the result and the count in the same query.
Thanks

MongoDB projection. Operator $add field|expression array awareness or after $slice

I've got collection that looks like:
[{
"org": "A",
"type": "simple",
"payFor": 3,
"price": 100
},
{
"org": "A",
"type": "custom",
"payFor": 2,
"price": 115
},
{
"org": "B",
"type": "simple",
"payFor": 1,
"price": 110
},
{
"org": "B",
"type": "custom",
"payFor": 2,
"price": 200
},
{
"org": "B",
"type": "custom",
"payFor": 4,
"price": 220
}]
And need to produce result with query to perform group by "org" where payments appears for only first "payFor" prices in "type".
I'm trying to use expression result by $slice operator in $add but this is not works.
pipeline:
[{
"$group": {
"_id": {
"org": "$org",
"type": "$type"
},
"payFor": {
"$max": "$payFor"
},
"count": {
"$sum": 1
},
"prices": {
"$push": "$price"
}
}
},
{
"$group": {
"_id": "$_id.org",
"payments": {
"$push": {
"type": "$_id.type",
"forFirst": "$payFor",
"sum": {
"$cond": [
{
"$gte": [
"$payFor",
"$count"
]
},
{
"$add": {
"$prices": {
"$slice": "$count"
}
}
},
{
"$add": "$prices"
}
]
}
}
}
}
}]
I know that it is possible to traverse unwinded prices and pick only "payFor" count of them. but result collections are more rich than in example above and this operation will produce some unecessary overheads.
Need some advice from community. Please. Thanks.