I am having issues consolidating data from dictionaries - swift

This was written in swift but its more of a logic question hopefully someone can help with, I've been working on an app that takes expenses and then splits the totals between users based on which users were specified in the "owees" property of the expense. I was able to divvy out the totals by creating a dictionary for all the users with the key being their name and the value being more dictionaries for each of the other users with the key being the other users' name, and the values being the amount owed (postive number if the money is owed to the parent dictionary, negative number for the opposite), my issue is now consolidating all the money so that all the users owed amounts are divvied out amongst each other (e.g.: if User1 owes User2 $10 but User2 owes User3 $5 then User1 now only owes User2 $5 but now also owes User3 $5 and User2's debt is cleared)
I know its seems confusing with the dictionary-inception but here is an example of the dictionary, and a link to my .playground where it shows the idea of what I am trying to and how I set it up, the last for loop is the problem, maybe theres a better way?
User1[
User2: -20
User3: 10
User4: -5
]
User2[
User1: 20
User3: -15
User4: 0
]
gist link:
https://gist.github.com/wilks7/0c5e3ab4f5d95c945579
playground file:
https://www.dropbox.com/s/6h2iuic84un2uh3/expenseSplit.playground.zip?dl=0

What you are trying to model is essentially a Directed Acyclic Graph. However if the queries that you need to make on the relationships are relatively simple (i.e. list the outstanding amounts for each person), then you may be able to get away with some object-oriented modelling rather than a complete DAG.. Constructing classes and embedding logic in those classes will make your code much easier to read compared to trying to accomplish the same thing with arrays and/or dictionaries.
A skeleton example is:
public class Debt {
var owedBy: Person
var amount: Float
init(amount: Float, from: Person) {
self.amount = amount
self.owedBy = from
}
}
public class Person {
var name: String
var loans: [Debt] = []
init(name: String) {
self.name = name
}
public func addLoan(debt: Debt) {
loans.append(debt)
}
public func showLoans() {
print("\(name):")
for debt in loans {
print("Owed \(debt.amount) by \(debt.owedBy.name)")
}
}
}
This would allow you to create loans and show what exists with code like:
let Bill = Person(name: "Bill")
let Tony = Person(name: "Tony")
Bill.addLoan(Debt(amount: 20.0, from: Tony))
Bill.showLoans()
Calling showLoans() for Bill as above would produce:
Bill:
Owed 20.0 by Tony

Related

How can I select in prisma the elements with a condition on a 1-N relation?

I have the following prisma schema
model User {
id Int #id #default(autoincrement())
userName string #unique
complaints Complaint[]
}
model Complaint {
id Int #id #default(autoincrement())
user User #relation(fields: [userId], references: [id])
creationTime DateTime #default(now())
userId Int
priority ComplaintPriority
}
enum ComplaintPriority {
HIGH
MEDIUM
LOW
}
I need to select the users that have last complaint (as last I mean the complaint with latest creationTime) with priority value HIGH.
In other words:
if an user has 3 complaints and the last of these complaints has high priority the user should be part of the result (ignoring previous complaints)
If an user has 8 complaints (maybe some of those with high priority) and the last one has low priority the user should not be part of the results
If the user has no complaints at all the user should not be part of the results
I didn't find the prisma syntax for this operation. Does anybody has any idea how to do it?
I looked into this a bit, unfortunately, I don't think there's a way to create a query exactly as you have in mind (as of version 3.5.0 of Prisma).
Here's a workaround that you could perhaps consider:
Fetch all user records that have at least one complaint with HIGH priority. Include complaint records and order them by creationTime.
Manually filter through the list in Node.js to keep appropriate user records.
let users = await prisma.user.findMany({
where: {
complaints: {
some: {
priority: "HIGH"
}
}
},
include: {
complaints: {
orderBy: {
creationTime: "desc"
}
}
}
})
users = users.filter(user => user.complaints[0].priority == "HIGH")
It should be noted though, this isn't perfectly optimal if there are really high number of user records. In such a case, I would consider creating a raw SQL query using rawQuery.

Build up IQueryable including additional tables based on conditions

I have an issue where we create a complex IQueryable that we need to make it more efficient.
There are 2 tables that should only be included if columns from them are being filtered.
My exact situation is complex to explain so I thought I could illustrate it with an example for cars.
If I have a CarFilter class like this:
public class CarFilter
{
public string BrandName { get;set; }
public decimal SalePrice {get; set; }
}
Let's say that we have a query for car sales:
var info = from car in cars
from carSale in carSales on carSale.BrandId == car.BrandId && car.ModelId == carSale.ModelId
from brand in carBrands on car.BrandId == brand.BrandId
select car
var cars = info.ToList();
Let's say that this is a huge query that returns 100'000 rows as we are looking at cars and sales and the associated brands.
The user only wants to see the details from car, the other 2 tables are for filtering purposes.
So if the user only wants to see Ford cars, our logic above is not efficient. We are joining in the huge car sale table for no reason as well as CarBrand as the user doesn't care about anything in there.
My question is how can I only include tables in my IQueryable if they are actually needed?
So if there is a BrandName in my filter I would include CarBrand table, if not, it's not included.
Using this example, the only time I would ever want both tables is if the user specified both a BrandName and SalePrice.
The semantics are not important here, i.e the number of records returned being impacted by the joins etc, I am looking for help on the approach
I am using EF Core
Paul
It is common for complex filtering. Just join when it is needed.
var query = cars;
if (filter.SalePrice > 0)
{
query =
from car in query
join carSale in carSales on new { car.BrandId, car.ModelId } equals new { carSale.BrandId, carSale.ModelId }
where carSale.Price >= filter.SalePrice
select car;
}
if (!filter.BrandName.IsNullOrEempty())
{
query =
from car in query
join brand in carBrands on car.BrandId equals brand.BrandId
where brand.Name == filter.BrandName
select car;
}
var result = query.ToList();

Understanding LinkingObjects in Realm Xcode 12, Also when to use it

In Realm, I had problem understanding ( Im new in Realm T,T ) the implementations of LinkingObjects , let's say a Person could have more than one Dog ( List of Dog ) so I would write the code such as below:
Person : Object {
dynamic var name:String = ""
let dogs = List<Dog>()
}
Dog : Object {
dynamic var name: String = ""
let walkers = LinkingObjects<fromType: Person.self, property:"dogs">
}
lets say
Person A
dogs = [Alex,Cindy]
Person B
dogs = [Doggo,Kiba]
if I delete Alex using Realm.delete then it become Person A dogs = [Cindy]
this is quite straight forward.
but when I remove LinkingObjects from the class such as below:
Person : Object {
dynamic var name:String = ""
let dogs = List<Dog>()
}
Dog : Object {
dynamic var name: String = ""
}
the app still can run normally without any diff, I can still add Person 3 and append a list of Dog. Also when deleting ( Realm.delete ) there is no difference as when I'm adding LinkingObject to the Dog class. what's the difference here? When can I use LinkinObject? Can anyone please explain? or write some more understandable code?
Already read all the previous answer but still I need another explanation. Thank You So Much!!
You can think of LinkingObjects almost as a computed property - it automagically creates an inverse link to the parent object when the child object is added to the parent objects List.
So when a Dog is added to a person's dogs list, a person reference is added to the Dog's walkers list. Keeping in mind that it's a many to many relationship so technically if Person A adds Doggo, and Person B adds Doggo, the Doggo's inverse relationship 'walkers' will contain Person A and Person B
the app still can run normally without any diff
Which is true, it doesn't affect he operation of the app. HOWEVER the difference is that by removing the walkers LinkingObjects, there's no way to query Dogs for their Person and get Dog Results (i.e. you can't traverse the graph of the relationship back to the person)
In other words we can query Person for kinds of dog stuff
let results = realm.objects(Person.self).filter("ANY dogs.color == 'brown'")
which returns a results object contains Persons that have a brown dog. However, we don't know which dog they have is brown; could be one, could be three.
However, suppose you want to get a results object containing specific brown dogs and want the owners name for each - you can't really do that without an inverse relationship (LinkingObjects)
let dogResult = realm.object(Dog.self).filter("color == 'brown'")
for dog in dogResult {
let person = dog.walkers.first!.name //assume there is only one owner
print(person.name)
}
The dogResults will only contain brown dogs, and you know specifically which ones they are.
So that's a big difference; without LinkingObjects we rely on returning Person objects and then iterating or processing each to get to the data we want. With LinkingObjects we can specifically get the objects we want to work with.
It's super handy when you want to add an observer to results to watch for changes - say on Brown dogs - to be notified of changes.

Grails 3 & relational domain mapping with Mongo

Trying to figure out if there is a way that I can relate these two domain objects in a similar way that I would if I were connected to an Oracle db.
gradle.properties
grailsVersion=3.2.9
gradleWrapperVersion=2.9
gormVersion=6.1.3.RELEASE
build.gradle
compile "org.grails.plugins:mongodb:6.1.3"
compile "org.mongodb:mongodb-driver:3.4.2"
Domain objects:
class Store {
Long id
// other properties
Long sellerId
}
class Seller {
Long id
// other properties
}
I thought to do something like this:
class Store {
Long id
// other properties
Long sellerId
Seller seller
Seller getSeller {
Seller.findById(this.sellerId)
}
}
In the case above, only sellerId is persisted to Mongo since it is not marked as embedded. This works great if I reference it in grails code - giving me valid values for all of the properties in store.seller. However, if I return a store from a controller, store.seller does not come through fully. The response JSON for store looks like this (notice how seller ONLY has the id property):
{
id: 1,
// other properties
seller: {
id: 22
}
}
I have also tried something like this but afterLoad never gets hit:
class Store {
Long id
// other properties
Long sellerId
Seller seller
def afterLoad() {
seller = Seller.findById(this.sellerId)
}
}
Is there a better way to go about doing this?

count multiple relations results with a single Parse query

I'm having a very simple setup with _User entity having a likes Relation with itself (reflective).
A common use case is list users.
I'm listing very few users (ex: 15), but i would also like to display the amount of likes he has.
Following standard suggested technique from Parse.com that would require a query for each of the 15 _User(s).
I don't think this is acceptable, maybe 2 queries are enough:
first one getting the first 15 _User(s)
second one getting the amount of likes each of the _User haves
But I have no idea if that's even possible with Parse API, so I'm asking for help ;)
If the column is a relation, then yes, getting the count will require a query per user.
If you expect the number of likes per user to be low (<100 is my semi-arbitrary rule of thumb), you could instead model likes as an array of pointers.
With that, you can know the count just by having the record in hand (i.e. someUser.get("likes").length). Even better, query include will eagerly fetch the related users...
userQuery.include("likes");
userQuery.find().then(function(users) {
if (users.length) {
var someUser = users[0];
var likes = someUser.get("likes");
if (likes.length) { // see, we can get the count without query
var firstLike = likes[0]; // we can even get those other users!
var firstLikeEmail = firstLike.get("email");
}
}
});
Otherwise, using relations, you're stuck with another query...
userQuery.find().then(function(users) {
if (users.length) {
var someUser = users[0];
var likes = someUser.get("likes");
return likes.query().count();
} else {
return 0;
}
}).then(function(count) {
console.log("the first user has " + count + " likes");
});