mongodb: delete object within an array, nested within two objects - mongodb

I am trying to delete an object within an array. But that array is nested within two objects. How do I do this?
For example: let's say I want to delete the transaction with
_id: 58c3154a19f82c0ddc53f0de
How would I do this??
{
"_id": {
"$oid": "58bad6cf93ab9703da331e25"
},
"username": "david.lam#transfast.com",
"password": "sha1$fc05ad7d$1$1cc86a287642516f947fda520ae8ddd42e983e23",
"firstName": "David",
"lastName": "David",
"transactions": {
"2017": {
"3": [
{
"where": "Duane Reade",
"what": "asdf",
"category": 6,
"amount": "34",
"_id": {
"$oid": "58c300ef1602f90c7166cbfb"
},
"date": {
"day": 10,
"month": 3,
"year": 2017
}
},
{
"where": "Amazon",
"what": "asdf",
"category": 2,
"amount": "100",
"_id": {
"$oid": "58c3154a19f82c0ddc53f0de"
},
"date": {
"day": 10,
"month": 3,
"year": 2017
}
}
]
}
}
}

To do so you need to use the $pull operator. Address array elements with the dot notation. The following query does the job:
db.user1.update({},
{$pull: {'transactions.2017.3': {_id: ObjectId("58c3154a19f82c0ddc53f0de")}}
});

Related

How can I compute the income of the sellerId of the products?

I'm trying to learn the advanced mongodb+mongoose function, so this is the result of my orders, and what I'm trying to do here is to compute the total amounts related to the sellerId
So in this one, I have two documents, the document 1 have an amount of 99 and and the other one is 11
so I need to get the sum of two. I've been searching and found the aggregate, but I can't figure out how I can combine the two documents.
[
{
"_id": "6360d1d0bd860240e2589564",
"userId": "6360cf687e186ebe29ab2a29",
"products": [
{
"productId": "6360cdd166480badb8c1e05b",
"quantity": 1,
"sellerId": "6360c6ed05e1e99034b5f7eb",
"_id": "6360d1d0bd860240e2589565"
}
],
"amount": 99,
"location": "asdsad",
"time": "asdsad",
"status": "pending",
"tax": 0.99,
},
{
"_id": "6360d7978044f3048e59bf34",
"userId": "6360d50dbd860240e258c585",
"products": [
{
"productId": "6360d7528044f3048e59bb6c",
"quantity": 1,
"sellerId": "6360d4d5bd860240e258c582",
"_id": "6360d7978044f3048e59bf35"
},
{
"productId": "6360d7868044f3048e59bd8c",
"quantity": 1,
"sellerId": "6360d4d5bd860240e258c582",
"_id": "6360d7978044f3048e59bf36"
}
],
"amount": 11,
"location": "Gym",
"time": "8:00 AM",
"status": "pending",
"tax": 0.11,
}
]
This might helps.
db.collection.aggregate([
{
$group: {
_id: null,
count: {
$sum: "$amount"
}
}
}
])

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

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

mongodb inner object to parent level

I got result after aggregate like
{
data: [
{
"_id": "61922aed85c74b2d1ef671bb",
"employee": {
"firstName": "fname",
"lastName": "lname",
"middleName": "mname"
},
"days": [
{
"_id": "61922aed85c74b2d1ef671be",
"day": "2021-09-01T21:00:00.000Z",
"data": {
"hours": 0,
"type": "OT",
"_id": "61922aed85c74b2d1ef671bf",
"updateDate": "2021-11-15T09:39:57.624Z"
}
},
{
"_id": "61922aed85c74b2d1ef671c0",
"day": "2021-09-02T21:00:00.000Z",
"data": {
"hours": 0,
"type": "OT",
"_id": "61922aed85c74b2d1ef671c1",
"updateDate": "2021-11-15T09:39:57.625Z"
}
}
]
}
]
}
Is it possible extract inner object of data of days array to the parent level.
From this
{
"_id": "61922aed85c74b2d1ef671be",
"day": "2021-09-01T21:00:00.000Z",
"data": {
"hours": 0,
"type": "OT",
"_id": "61922aed85c74b2d1ef671bf",
"updateDate": "2021-11-15T09:39:57.624Z"
}
}
to this
{
"_id": "61922aed85c74b2d1ef671be",
"day": "2021-09-01T21:00:00.000Z",
"hours": 0,
"type": "OT",
"updateDate": "2021-11-15T09:39:57.624Z"
}
Simply use $project like this:
db.collection.aggregate([
{
"$project": {
"day": 1,
"hours": "$data.hours",
"type": "$data.type",
"updateDate": "$data.updateDate"
}
}
])
Example here
Or to update values inside the array:
db.collection.aggregate([
{
"$project": {
"_id": 1,
"employee": 1,
"days": {
"$map": {
"input": "$days",
"as": "d",
"in": {
"_id": "$$d._id",
"day": "$$d.day",
"hours": "$$d.data.hours",
"type": "$$d.data.type",
"updateData": "$$d.data.updateDate"
}
}
}
}
}
])
Example here

Group by an optional field in mongodb

I would like to independently group the results of an or clause, including overlap. The data set is rather large so running 2 queries sequentially will result in an undesirable wait time. I am hoping I can somehow project which clause returned the corresponding data. Given this data set:
[
{
"_id": 1,
"item": "abc",
"name": "Michael",
"price": NumberDecimal("10"),
"quantity": NumberInt("2"),
"date": ISODate("2014-03-01T08:00:00Z")
},
{
"_id": 2,
"item": "jkl",
"name": "Toby",
"price": NumberDecimal("20"),
"quantity": NumberInt("1"),
"date": ISODate("2014-03-01T09:00:00Z")
},
{
"_id": 3,
"item": "xyz",
"name": "Keith",
"price": NumberDecimal("5"),
"quantity": NumberInt("10"),
"date": ISODate("2014-03-15T09:00:00Z")
},
{
"_id": 4,
"item": "abc",
"name": "Dwight",
"price": NumberDecimal("5"),
"quantity": NumberInt("20"),
"date": ISODate("2014-04-04T11:21:39.736Z")
},
{
"_id": 5,
"item": "abc",
"name": "Ryan",
"price": NumberDecimal("10"),
"quantity": NumberInt("10"),
"date": ISODate("2014-04-04T21:23:13.331Z")
},
{
"_id": 6,
"item": "def",
"name": "Jim",
"price": NumberDecimal("7.5"),
"quantity": NumberInt("5"),
"date": ISODate("2015-06-04T05:08:13Z")
},
{
"_id": 7,
"item": "abc",
"name": "Keith",
"price": NumberDecimal("7.5"),
"quantity": NumberInt("10"),
"date": ISODate("2015-09-10T08:43:00Z")
},
{
"_id": 8,
"item": "abc",
"name": "Michael",
"price": NumberDecimal("10"),
"quantity": NumberInt("5"),
"date": ISODate("2016-02-06T20:20:13Z")
},
]
I would like to receive this result:
[{
"_id": {
"name": "Keith"
},
"count": 2
},
{
"_id": {
"item": "abc",
},
"count": 5
}]
Here is what I have tried so far:
db.collection.aggregate([
{
$match: {
$or: [
{
item: "abc"
},
{
name: "Keith"
}
]
}
},
{
$group: {
_id: {
item: "$item",
name: "$name"
},
count: {
$sum: 1
}
}
}
])
You can use $facet to get multiple aggregation pipelines into the same stage in this way:
Using $facet there are two "outputs" one group by name and other by item.
In each one there are multiple stages:
First $match to process only documents you want.
Then $group with _id name or item, and $count to get the total.
db.collection.aggregate([
{
"$facet": {
"groupByName": [
{
"$match": {"name": "Keith"}
},
{
"$group": {"_id": "$name","count": {"$sum": 1}}
}
],
"groupByItem": [
{
"$match": {"item": "abc"}
},
{
"$group": {"_id": "$item","count": {"$sum": 1}}
}
]
}
}
])
Example here
The output is:
{
"groupByItem": [
{
"_id": "abc",
"count": 5
}
],
"groupByName": [
{
"_id": "Keith",
"count": 2
}
]
}
Here it is:
mongos> db.n.aggregate([ { $facet:{ names:[ {$match:{name:"Keith"}} , {$group:{_id:{name:"$name"}, count:{$sum:1}}} ] , items:[ {$match:{item:"abc"}},{ $group:{_id:{item:"$item"}, count:{$sum:1}} } ] } } , {$project:{ "namesANDitems":{$concatArrays:[ "$names","$items" ]} }} ,{$unwind:"$namesANDitems"} ,{$replaceRoot:{newRoot:"$namesANDitems"} } ]).pretty()
{ "_id" : { "name" : "Keith" }, "count" : 2 }
{ "_id" : { "item" : "abc" }, "count" : 5 }
mongos>
explained:
You create two pipes via $facet
Match in every facet pipe what you need to group pipe1=names , pipe2=items
Join the arrays from the two pipes in single array named "namesANDitems"
Convert the array to object with $unwind
Remove the temporary object name namesANDitems so you have only the two objects as requested

select documents grouped by field

I have this documents of movie showing time and date:
`{
"_id": ObjectId("5628668c3e82c49245b7acdc"),
"ticketID": ObjectId("5606d36b5fbd7d76028b4b08"),
"uid": "50000",
"day": "Friday",
"date": "2015-10-23 21:05:00",
"adult": NumberLong(550),
"student": NumberLong(550),
"children": NumberLong(250),
"limit": NumberLong(20),
"sold": NumberLong(0)
},{
"_id": ObjectId("562866013e82c49045b7acdc"),
"ticketID": ObjectId("5606d36b5fbd7d76028b4b08"),
"uid": "50000",
"day": "Friday",
"date": "2015-10-23 19:30:00",
"adult": NumberLong(1050),
"student": NumberLong(800),
"children": NumberLong(550),
"limit": NumberLong(20),
"sold": NumberLong(0)
},{
"_id": ObjectId("562865013e82c49845b7acda"),
"ticketID": ObjectId("5606d36b5fbd7d76028b4b08"),
"uid": "50000",
"day": "Friday",
"date": "2015-10-23 18:45:00",
"adult": NumberLong(1500),
"student": NumberLong(750),
"children": NumberLong(750),
"limit": NumberLong(20),
"sold": NumberLong(0)
}
`
I want to group the final result by "day" where "ticketID" matches, "date" as an object and adding "adult","student","children","limit" to an array
-- UPDATE --
I would like the returned structure to follow:
{
"_id": "ticketID",
"day": "Friday",
"items": [
{
"date": date,
"time": time"adult": price,
"children": price,
"student": price,
"limit": value
},
{
"date": date,
"time": time"adult": price,
"children": price,
"student": price,
"limit": value
},
{
"date": date,
"time": time"adult": price,
"children": price,
"student": price,
"limit": value
}
]
}
Run the following aggregation pipeline which uses the $group operator to group your documents by the specified fields, add the items array by using the accumulator operator $push that returns an array of expression values for each group. The $project pipeline operator then reshapes the documents by amending the fields to get the final desired structure:
var pipeline = [
{
"$group": {
"_id": {
"ticketID": "$ticketID",
"day": "$day"
},
"items": {
"$push": {
"date": "$date",
"time": "$time",
"adult": "$adult",
"children": "$children",
"student": "$student",
"limit": "$limit"
}
}
}
},
{
"$project": {
"_id": "$_id.ticketID",
"day": "$_id.day",
"items": 1
}
}
];
db.collection.aggregate(pipeline);