Filter Realm Objects to Only Get One (Distinct) Object by Attribute

Filter realm objects to only get one (distinct) object by attribute

As of Realm Swift 3.1 you can do let movies = realm.objects(Movie.self).sorted(by: ["id", true]).distinct(by: ["genre"]), which will select the first Movie of each genre using the sort order applied before the distinct operation.

How to get unique value from Realm database in swift

Starting from Realm 3.10 it's now possible to

Add Results.distinct(by:) / -[RLMResults
distinctResultsUsingKeyPaths:], which return a Results containing only
objects with unique values at the given key paths.

Old response - before Realm 3.10

It is not possible yet to obtain a "distinct"-like functonality from a Realm query (track the open issue here)

However, there are some workarounds suggested in the thread I mentioned above (please read it to get the full context), by user apocolipse :

// Query all users
let allUsers = Realm().objects(User)

// Map out the user types
let allTypes = map(allUsers) { $0.type }

// Fun part: start with empty array [], add in element to reduced array if its not already in, else add empty array
let distinctTypes = reduce(allTypes, []) { $0 + (!contains($0, $1) ? [$1] : [] )

Or better yet, a different approach using Sets (by user jpsim):

let distinctTypes = Set(Realm().objects(User).valueForKey("type") as! [String])

Obviously the workarounds aren't as efficient as a direct DB query, so use with care (and testing under realistic load).

Return unique/distinct values with Realm query

I found out Realm doesn't fully support distinct queries yet. The good news is I also found a workaround for it, on this github issue.

Objective-c

RLMResults *messages = [Message allObjects];
NSMutableArray *uniqueIDs = [[NSMutableArray alloc] init];
NSMutableArray *uniqueMessages = [[NSMutableArray alloc] init];
for (Message *msg in messages) {
NSString *jabberID = msg.jabberID;
Message *uniqueMSG = (Message *)msg;
if (![uniqueIDs containsObject:jabberID]) {
[uniqueMessages addObject:uniqueMSG];
[uniqueIDs addObject:jabberID];
}
}

Swift 3.0

let realm = try! Realm()
let distinctIDs = Set(realm.objects(Message.self).value(forKey: "jabberID") as! [String])
var distinctMessages = [Message]()
for jabberID in distinctIDs {
if let message = realm.objects(Message.self).filter("jabberID = '\(jabberID)'").first {
distinctMessages.append(message)
}
}

Realm Filter Issue

Let me shorten and repeat the question

The objective is to get the qty of a particular InventoryModel based on the
StockModel quantities stored in the ofStock list. (instead of storing
it in InventoryModel totalUnit property).

Using the InventoryModel and StockModel in the question, if we create an inventory model for widget

let inv = InventoryModel()
inv.name = "Widget"

and then add two StockModel objects to its ofStock List

let sm0 = StockModel()
sm0.quantity = 1

let sm1 = StockModel()
sm1.quantity = 2

inv.ofStock.append(objectsIn: [s0, s1])

If we then want to get the total inventory available for the Widget object, it's a single line

let sum: Int = realm.objects(StockModel.self).filter("ANY parentInventory.name == 'Widget'").sum(ofProperty: "quantity")
print(sum)

and the output is 3

Note that we are transversing back through the StockModels to get the parent they belong to.

EDIT

The OP also wanted to have a query to do the following (from the comments)

I want to query for all InventoryModels that have ANY stock models
that have a quantity > 0

Here's the query that returns all InventoryModel objects where any StockModels in the ofStock property have a quantity property greater than 0

let results = realm.objects(InventoryModel.self).filter("ANY ofStock.quantity > 0")

Realm - how to query for a List greater than 0 objects

I was so close!

    let results = realm.objects(Person.self).filter("cats.@count > 0")

(needed the "@" before count)

How to address key of retrieved object, in Realm, Swift?

You are using a property called name in your filter string but in your UserRecords class the property is called username. Also you have to create the filter string differently:

var currentlogin = realm.objects(UserRecords).filter("username = '\(LogUsernameTextField.text!)'")

Also be aware that the filter method returns a list of UserRecord objects that match the filter and not a single object. So calling if currentlogin.password == ... will cause an error.

The list only has 1 item (because the username is unique) but it is still a list. So to access the UserRecord object you can call first:

var currentlogin = realm.objects(UserRecords).filter("name = LogUsernameTextField.text!").first 

Also the text property of UITextField returns an Optional, so you have to unwrap it.



Related Topics



Leave a reply



Submit