Mongo complex multi sort - mongodb

I would like to know if mongo lets you do complex multi sorting and how to do it.
Imagine that you have Products with two bollean (0/1) fields "Sale" & "Focus" and a price (double).
I would like to return all products but order then by:
1- Products on Focus and on Sale
2- Products on Focus
3- Products on Sale
and inside each one of this three groups they should be ordered by price desc
Is this even doable in a single query sort?

Related

MongoDb two collections or one?

I am beginner in Mongodb.
I have a products collection with details:
products:[
{
id: 1,
name: "CocaCola",
discount: true
}
]
Some products may have a discount. For that I decided to add property:
{ discount: true }
Should I create a separated discounts_products collection to store details of discount or better includ all information directly in product.discount?
I am a bit confused after related databases.
I try to consider this step from others sides (insert ,update and reading data)
I suggest you to have that as a field.
Instead of a boolean flag, you can keep how much percentage discount is.
If it is boolean
You can check for $exists on discount field to find discounted field.
If it is a number
You can use $gte, $lte to find products with more or less than particular discount.
About non discount products
It is not mandatory that all documents/rows should have that field. You can opt out that field for the product which doesn't have discount.
If you need boolean for particular use case, then you need additional field to store how much percent discount is.
Reason to avoid separate collection:
There could be a use case where you need to get both discounted and non discounted products. You need to make two http requests.
You need to move/delete product forth and back between two collections when product goes from discounted to non discounted.
In cases of single collection, you can remove this field when the product becomes non discounted or you can set as false if you keep boolean or you can set as 0 if you plan to keep a number.
If it is a complex object, you can have a nested object like
{
_id:12,
product_name : "phone",
discount: {
startTime:time,
.... OtherFields
}
}
Mongodb is designed to get rid of the relational data, use that to get the benefit from this pattern and the high performance that you would expect.
So my answer will be to add the discounts to the property in products.
By inserting you could maybe insert it with the value null when that is the default behaviour, otherwise just add the amount of discount or whatever you have to add to it, updating and reading date will be the same (checking if not null).

MongoDB Querying Large Datasets

Lets say I have simple document structure like:
{
"item": {
"name": "Skittles",
"category": "Candies & Snacks"
}
}
On my search page, whenever user searches for product name, I want to have a filter options by category.
Since categories can be many (like 50 types) I cannot display all of the checkboxes on the sidebar beside the search results. I want to only show those which have products associated with it in the results. So if none of the products in search result have a category, then do not show that category option.
Now, the item search by name itself is paginated. I only show 30 items in a page. And we have tens of thousands of items in our database.
I can search and retrieve all items from all pages, then parse the categories. But if i retrieve tens of thousands of items in 1 page, it would be really slow.
Is there a way to optimize this query?
You can use different approaches based on your workflow and see what works the best in your situation. Some good candidate for the solution are
Use distinct prior to running the query on large dataset
Use Aggregation Pipeline as #Lucia suggested
[{$group: { _id: "$item.category" }}]
Use another datastore(either redis or mongo itselff) to store intelligence on categories
Finally based on the approach you choose and the inflow of requests for filters, you may want to consider indexing some fields
P.S. You're right about how aggregation works, unless you have a match filter as first stage, it will fetch all the documents and then applies the next stage.

Sorting in Elasticsearch based on Multiple indices

I need to perform sorting on Elasticsearch documents...
I have one index created for MongoDB collections 'products', which have price and product ratings in it.
I have another collection 'product_hits' in which I am save one record (product_id, IP etc.) on every click of particular product by user. Now I want to sort product documents on by considering Product hit count (maybe which I can get through aggregation), price and product rating.
In short I want to rank all the products based on price and popularity as other sites does.
How can I achieve this in elasticsearch?
I gone though scripting of elasticsearch and I am able to sort on price and product rating..... but I didn't find anything useful in which we can perform sort based on multiple indices.
is it possible?? or do I have to sort all records on my own through coding?
I am using play framework.
I hope this question can be understood... Its complex..!!!

Sort on none-unique field and pagination mongo

If I want to sort by product price, when I apply skip and limit it works if prices are distinct but if they are all the same, pagination breaks (next page result isn't expected, it shows already shown results), as if sorting products is computed differently everytime. So I'm wondering is adding product _id (which is unique) to sort: {product_price:1, product_id:1} correct to ensure that my pagination won't break (so that sort is ordered equally everytime). Is there something else I should be aware?
Thanks

mongoDB many to many with one query?

in mysql i use JOIN and one query is no problem. what about mongo?
imagine categories and products.
products may have more categories.
categories may have more product.
(many to many structure)
and administrator may edit categories in administration (categories must be separated)
its possible write product with categories names in one query?
i used this structure
categories {
name:"categoryName",
product_id:["4b5783300334000000000aa9","5783300334000000000aa943","6c6793300334001000000006"]
}
products {
name:"productName",
category_id:["4b5783300334000000000bb9","5783300334000000000bb943","6c6793300334001000000116"]
}
now i can simply get all product categories, and product in some category and categories alone for editation. but if i want write product with categories names i need two queries - one to get product categories id and second to get categories names from categories by that ids.
is this the right way? or this structure is unsuitable? i would like to have only one query but i dont know if its possible.
Yep, MongoDB is specifically bad at this particular type of operation. However, it's also a matter of scope. If you have 30 million products and you want to join the 3 million Products to their Category, you'll find that it's not very quick in many Databases (even though it's one line of code).
What MongoDB requires here is some de-normalization.
Your collections will probably look like this:
categories {
_id:"mongoid",
name:"categoryName",
...
}
products {
_id:"mongoid",
name:"productName",
categories:[
{"4b5783300334000000000bb9":'categoryName'},
{"5783300334000000000bb943":'CategoryName2'},
{"6c6793300334001000000116":'categoryName3'}
]
}
Here's how it will work (rough estimate, don't have my Mongo instance handy):
Grab products and their categories
db.products.find({"_id": {$in:[1,2,3]}, {name:1,categories:1})
Grab products with a certain category:
db.products.find({"categories.0": {$in:[x,y,z]}},{categories:1,name:1} }
Yes, it's not quite the same. And you will have to will have to update all of the product records when you change the name of a category. I know this seems weird, but this is standard for denormalization.
BTW, I'm assuming here that you're going to have lots of products and significantly less categories. This method is probably best if you have say 100 items in each category. If you have 5 items in each category, then you'll probably want to store more of the category information in each item.
Yes it's the only way you have. There are no join possibility.
But you can add a lot of information in your categories or product document like :
categories {
name:"categoryName",
product_id:[ {"4b5783300334000000000aa9": 'productName'},{"5783300334000000000aa943":'productName2'},{"6c6793300334001000000006":'productName3'}]
}
products {
name:"productName",
category_id:[{"4b5783300334000000000bb9":'categoryName'},{"5783300334000000000bb943":'CategoryName2',{"6c6793300334001000000116":'categoryName3'}]
}
But you need made some callback for update all document when on is change.