Nested search/filtering with Laravel/Eloquent - sql

Let's say i have a table of houses, each of which has many rooms, each of which has many items in it. Each item has a color.
Houses
+ id
+ name
Rooms
+ id
+ house_id (FK house.id)
+ name
Items
+ id
+ room_id (FK room.id)
+ name
+ color
The corresponding model relationships ($this->hasMany()) has been set up.
I then want to return a nested JSON object with all the red items in it, with the houses as the top level of the object. That is, the JSON object is structured as a list of houses, each of which has a list of rooms, each of which has a list of items.
To be clear: If a house has no rooms with a red item in it, i don't want the house to be in the JSON object at all. If it only has some rooms with red items in it, i only want those rooms in the object. And finally of course, for the rooms with red items in it, i only want those red items to be in the object.
How can i best do this using constraints like ->where(), or if not possible, how can i best use raw queries to do it?
EDIT:
I already did create a nested query using whereHas, something along the lines of:
House::whereHas('rooms', function ($rooms) {
$rooms->whereHas('items', function ($items) {
$items->where('color', 'red);
});
});
While this only gave me houses that had red items in it, it keeps the non-red items of those houses in the object as well.

To filter out rooms there is not red i believe you can utilize with() the optional query.
House::with(['rooms.items' => function($query) {
$query->where('color', 'red');
}])->whereHas('rooms', function ($rooms) {
$rooms->whereHas('items', function ($items) {
$items->where('color', 'red);
});
});

Related

Creating a shop/ item system in flutter with SQL, how to structure in-game/app items properly?

New to SQL & databases, creating an in-app shop that holds different items.
void _createTableItems(Batch batch) {
batch.execute('DROP TABLE IF EXISTS Items');
batch.execute('''CREATE TABLE boughtItems (
id INTEGER PRIMARY KEY,
price INTEGER
)''');
}
class Item {
Item({required this.id, required this.price, required this.title});
String title;
int id;
int price;
}
List<Item> availableProducts = [WeaponItem(id: 0, strength: 5), WeaponItem(id: 1, strength: 7), StableItem(id: 2, speed: 4), FoodItem(id: 3, rev: 7)]
I pretty much have the most basic strucutre possible right now.
When I need to get the products, all I do is search the availableProducts list of items for ID's in the database query.
Future<List<Item>> getBought() async {
await database;
List products = await _database!.query("Items");
List<Item> result = [];
for (var element in products) {
result.add(availableProducts.where((e) => e.id == element["id"]).first);
}
return result;
}
Is this an acceptable way to do this?
What I'm worried about is the mixing of item types.
I'm a bit lost since there's multiple things I could do. Should I create a different table holding all the properties of each individual items? Should I add a type string to the table to differentiate the different items?
I would create one table for example products. This table
has general information about the products(id, name, product_number, info) that all products have in common. If you want additional and different information for every product type, I would add a fk_type which references to a product_type(id, name) table that stores the different product types. Then I would create an additional table for every product type. Ex: product_weapon(id, size, ammunition, reload_time ), product_chair(id, high, depth, weight). But you can also work just with the simple product table and add general description fields that could store jsons, xmls, css files.

How to modify value in column typeorm

I have 2 tables contractPoint and contractPointHistory
ContractPointHistory
ContractPoint
I would like to get contractPoint where point will be subtracted by pointChange. For example: ContractPoint -> id: 3, point: 5
ContractPointHistory has contractPointId: 3 and pointChange: -5. So after manipulating point in contractPoint should be 0
I wrote this code, but it works just for getRawMany(), not for getMany()
const contractPoints = await getRepository(ContractPoint).createQueryBuilder('contractPoint')
.addSelect('"contractPoint".point + COALESCE((SELECT SUM(cpHistory.point_change) FROM contract_point_history AS cpHistory WHERE cpHistory.contract_point_id = contractPoint.id), 0) AS points')
.andWhere('EXTRACT(YEAR FROM contractPoint.validFrom) = :year', { year })
.andWhere('contractPoint.contractId = :contractId', { contractId })
.orderBy('contractPoint.grantedAt', OrderByDirection.Desc)
.getMany();
The method getMany can be used to select all attributes of an entity. However, if one wants to select some specific attributes of an entity then one needs to use getRawMany.
As per the documentation -
There are two types of results you can get using select query builder:
entities or raw results. Most of the time, you need to select real
entities from your database, for example, users. For this purpose, you
use getOne and getMany. But sometimes you need to select some specific
data, let's say the sum of all user photos. This data is not an
entity, it's called raw data. To get raw data, you use getRawOne and
getRawMany
From this, we can conclude that the query which you want to generate can not be made using getMany method.

Join multiple tables - Flutter - Firebase

I have three collections: Cars, Makes, Models. A car has a make, model and price. The reason why I have separate collections is because I would like to display the makes on their own and models on their own eventually.
I would like to display each car with its make, model and price.
In SQL I can join the tables and compare by Id's. I'm not sure how I can replicate a join in nosql.
in NoSQL, you can't do it in one query. you have to divided to multiple queries :
first query : to get the data from the main table (in your case: Cars module)
second query: to get the data from the joined tables ( Makes, Models )
for example using JavaScript
carTable.on('value', function (snapshot) {
var makeID = snapshot.val().makeID;
makesTable.child('makes').child(makeID).once('value', function(mediaSnap) {
console.log(makeID + ":" + mediaSnap.val());
});
var modelsID = snapshot.val(). modelsID;
modelsTable.child('models').child(modelsID).once('value', function(mediaSnap) {
console.log(modelsID + ":" + mediaSnap.val());
});
});
so, you have to join the tables in 2 steps.

Magento: Get Collection of Order Items for a product collection filtered by an attribute

I'm working on developing a category roll-up report for a Magento (1.6) store.
To that end, I want to get an Order Item collection for a subset of products - those product whose unique category id (that's a Magento product attribute that I created) match a particular value.
I can get the relevant result set by basing the collection on catalog/product.
$collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToFilter('unique_category_id', '75')
->joinTable('sales/order_item', 'product_id=entity_id', array('price'=>'price','qty_ordered' => 'qty_ordered'));
Magento doesn't like it, since there are duplicate entries for the same product id.
How do I craft the code to get this result set based on Order Items? Joining in the product collection filtered by an attribute is eluding me. This code isn't doing the trick, since it assumes that attribute is on the Order Item, and not the Product.
$collection = Mage::getModel('sales/order_item')
->getCollection()
->join('catalog/product', 'entity_id=product_id')
->addAttributeToFilter('unique_category_id', '75');
Any help is appreciated.
The only way to make cross entity selects work cleanly and efficiently is by building the SQL with the collections select object.
$attributeCode = 'unique_category_id';
$alias = $attributeCode.'_table';
$attribute = Mage::getSingleton('eav/config')
->getAttribute(Mage_Catalog_Model_Product::ENTITY, $attributeCode);
$collection = Mage::getResourceModel('sales/order_item_collection');
$select = $collection->getSelect()->join(
array($alias => $attribute->getBackendTable()),
"main_table.product_id = $alias.entity_id AND $alias.attribute_id={$attribute->getId()}",
array($attributeCode => 'value')
)
->where("$alias.value=?", 75);
This works quite well for me. I tend to skip going the full way of joining the eav_entity_type table, then eav_attribute, then the value table etc for performance reasons. Since the attribute_id is entity specific, that is all that is needed.
Depending on the scope of your attribute you might need to add in the store id, too.

Select distinct active record

I have a model called Shops with an attribute called brands, brands is a text field and contains multiple brands. What i would like to do is select all unique brands and display them sorted in alphabetic order
#brands = Shop.all(:select => 'distinct(brands)')
What to do from here?
If Shop#brands can hold multiple values like for example: "rony, hoke, fike", then I can reluctantly suggest doing something like this:
#brands = Shop.all(:select => 'brands').each { |s|
s.brands.split(',').map { |b|
b.strip.downcase
}
}.flatten.uniq.sort
BUT, you should really think about your data model here to prevent such hackery. You couuld break out the brands into it's own table + model and do a many to many relationship with Shop.