Get the last document and filter nested array - mongodb

First time playing with MongoDB (and pymongo) and I have the documents below.
I'm trying to make the following query:
get the top 1 entry, ordered by time_added descending
from that subset of documents (let's call it entries.stocks), get the stocks that price is less than a balance value
order by volume and price in that order.
From what I've googled it seems this can be done with aggregation but I only managed to do the first step with:
db.entries.find().sort('date_added', -1).limit(1)
Documents:
[
{
"_id": {
"$oid": "5fcd2582a7a12288df9a6bf3"
},
"stocks": [
{
"name": "stock_name",
"volume": 73,
"price": 135
},
{
"name": "stock_name",
"volume": 44,
"price": 324
}
],
"date_added": {
"$date": "2020-12-06T18:40:02.000Z"
}
},
{
"_id": {
"$oid": "5fcd2582a7a12288df9a6ad0"
},
"stocks": [
{
"name": "stock_name",
"volume": 342,
"price": 43
},
{
"name": "stock_name",
"volume": 544,
"price": 66
}
],
"date_added": {
"$date": "2020-12-05T18:40:02.000Z"
}
}
]

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"
}
}
}
])

Finding the max date of each id from millions of data in mongodb

I have a collection as below and I need to find the max action time of the products in the list whose product_id is given.
In addition, since there are millions of data, it should be as stabilized as possible. Can you help me?
Example data: If productId is 125 or 126
[
{
"_id": "object",
"at": "2022-03-25 05:00:00",
"productId": 125
},
{
"_id": "object",
"at": "2022-03-25 04:00:00",
"productId": 125
},
{
"_id": "object",
"at": "2022-03-24 12:00:00",
"productId": 126
},
{
"_id": "object",
"at": "2022-03-25 08:00:00",
"productId": 127
}
]
Example output:
[
{
"_id": "object",
"productId": 125
"at": "2022-03-25 05:00:00"
},
{
"_id": "object",
"productId": 126,
"at": "2022-03-24 12:00:00"
}
]
Here's one way to get your desired output.
N.B.: There should be an index on "productId".
db.collection.aggregate([
{
"$match": {
"productId": {
"$in": [125, 126]
}
}
},
{
"$group": {
"_id": "$productId",
"newRoot": {
"$top": {
"sortBy": {
"at": -1
},
"output": "$$ROOT"
}
}
}
},
{"$replaceWith": "$newRoot"}
])
Try it on mongoplayground.net.

How can I get only specific object from nested array mongodb

I'm using mongoDB with PHP. I know how to get the document based on product_id, but I need only a specific object from the whole document, I don't know how to get only specific object from nested array based on product_id.
for ex. My expected output is:
products": [
{
"product_id": 547,
"name": "cola",
"quantity": 24
}
]
then make some changes on object p.s update the quantity then update it to the database.
My collection looks like
"_id": {
"$oid": "62ed30855836b16fd38a00b9"
},
"name": "drink",
"products": [
{
"product_id": 547,
"name": "cola",
"quantity": 24
},
{
"product_id": 984,
"name": "fanta",
"quantity": 42
},
{
"product_id": 404,
"name": "sprite",
"quantity": 12
},
{
"product_id": 854,
"name": "water",
"quantity": 35
}
]
}
Try this:
db.getCollection('test').aggregate([
{
"$unwind": "$products"
},
{
"$match": {
"products.product_id": 547
}
},
{
"$replaceRoot": {
"newRoot": {
"$mergeObjects": [
"$$ROOT",
"$products"
]
}
}
},
{
"$project": {
"products": 0
}
}
])
The query gives the following output:
{
"name" : "cola",
"product_id" : 547,
"quantity" : 24
}

MongoDB query to nested document returns nothing

Here is a sample product document stored in MongoDB:
[
{
"_id": "....",
"user_id": "....",
"username": "....",
// omitted
"product": {
"description": "A stunningly beautiful page with a constant growth of followers, etc. ❤",
"banner_img": "https://tse3-mm.cn.bing.net/th/id/OIP.jNCbt_c_8vnq7sbWluCVnQHaCG?w=300&h=85&c=7&o=5&pid=1.7",
"niches": "Fashion & Style",
"categories": [
{
"type": "Single",
"pricing": [
{
"time": 6,
"price": 15,
"bio_price": 10
},
{
"time": 12,
"price": 20,
"bio_price": 10
}
]
},
{
"type": "Multiple",
"pricing": [
{
"time": 12,
"price": 30.5,
"bio_price": 15
}
]
},
{
"type": "Story",
"pricing": [
{
"time": 24,
"price": 40,
"bio_price": 20
}
]
}
]
},
"created_at": "2020-01-11T18:19:54.312Z",
"updated_at": "2020-01-11T18:19:54.312Z"
}
],
I'd like to find an account that has a product with Multiple or Story pricing type. My query is as follows:
{
product: {
categories: {
pricing: {
$elemMatch: {
type: { $in: ['Multiple', 'Story'] }
}
}
}
}
}
I'm running this query with lucid-mongo in adonisjs framework.
It should at least return one document but it returns nothing.
I ran the query both in framework and on mongo.exe but not works.
What's wrong with my query?

Calculate aggregates in a bucket in Upsert MongoDB update statement

My application gets measurements from a device that should be stored in a MongoDB database. Each measurement contains values for several probes of the device.
The measurements should displayed in an aggregation for a certain amount of time. I'm using the Bucket pattern in order to prepare the aggregates and simplify indexing and querying.
The following sample shows a document:
{
"DeviceId": "Device1",
"StartTime": 100, "EndTime": 199,
"Measurements": [
{ "timestamp": 100, "probeValues": [ { "id": "1", "t": 30 }, { "id": "2", "t": 67 } ] },
{ "timestamp": 101, "probeValues": [ { "id": "1", "t": 32 }, { "id": "2", "t": 67 } ] },
{ "timestamp": 102, "probeValues": [ { "id": "1", "t": 34 }, { "id": "2", "t": 55 } ] },
{ "timestamp": 103, "probeValues": [ { "id": "1", "t": 27 }, { "id": "2", "t": 30 } ] }
],
"probeAggregates": [
{ "id": "1", "cnt": 4, "total": 123 },
{ "id": "2", "cnt": 4, "total": 219 }
]
}
Updating the values and calculating the aggregates in a single request works well if the document already exists (1st block: query, 2nd: update, 3rd: options):
{
"DeviceId": "Device1",
"StartTime": 100,
"EndTime": 199
},
{
$push: {
"Measurements": {
"timestamp": 103,
"probeValues": [ { "id": "1", "t": 27 }, { "id": "2", "t": 30 } ]
}
},
$inc: {
"probeAggregates.$[probeAggr1].cnt": 1,
"probeAggregates.$[probeAggr1].total": 27,
"probeAggregates.$[probeAggr2].cnt": 1,
"probeAggregates.$[probeAggr2].total": 30
}
},
{
arrayFilters: [
{ "probeAggr1.id": "1" },
{ "probeAggr2.id": "2" }
]
}
Now I want to extend the statement to do a upsert if the document does not exist yet. However, if I do not change the update statement at all, there is the following error:
The path 'probeAggregates' must exist in the document in order to apply array updates.
If I try to prepare the probeAggregates array in case of an insert (e.g. by using $setOnInsert or $addToSet), this leads to another error:
Updating the path 'probeAggregates.$[probeAggr1].cnt' would create a conflict at 'probeAggregates'
Both errors can be explained and seem legit. One way to solve this would be to change the document structure and create one document per device, timeframe and probe and by that simplify the required update statement. In order to keep the number of documents low, I'd rather solve this by changing the update statement. Is there a way to create a valid document in an upsert?
(as I'm just learning to use a document db, feel free to share your experience in the comments on whether it is a good goal to keep the number of documents low in real world scenarios)