kotlin map objects and filter from inner list

Issue

I’m making a DB request and getting back a list of objects. Within this list of objects is another list, which I want to filter on. After filtering, I then want to map the remaining objects to my domain model.

So I have my Database model:

data class TaskDatabaseModel(

    @PrimaryKey
    @ColumnInfo(name = "id")
    var id: String,

    @ColumnInfo(name = "task_categories")
    val categories: List<TaskCategory>,

    //Other fields
)

And my domain model:

@Parcelize
data class Task(
    val id: String,
    val taskCategories: List<TaskCategory> = listOf(TaskCategory(TaskCategoryType.GENERAL)),
    //Other fields
) : Parcelable

TaskCategory:

@Parcelize
data class TaskCategory(val type: TaskCategoryType, val id: String? = null) : Parcelable

My function to get the list:

override fun getTasks(taskId: String): Flowable<List<Task>> {
    return db.getTasksDao().getAllTasks()
        .map { taskList ->
            taskList.map { listTaskDbModel ->
                listTaskDbModel.mapToDomainModel(cache.getCurrentUserId())
            }
        }
        .filter { taskList ->
            taskList.find { it.taskCategories.find { category -> category.id == taskId } != null } != null
        }
}

The filter code returns all items and doesn’t filter.

How do I change it so I only return the objects that have the required id in the categories list? Would it be easier to do it on the DB query? The list is stored as JSON.

Thanks

Solution

I believe you are applying the filter on the wrong object. You’re applying it on the Flowable rather than on taskList. This means that if at least one task matches your condition, you’ll keep all tasks. The below should be correct if I understand your intent:

override fun getTasks(taskId: String): Flowable<List<Task>> {
    return db.getTasksDao().getAllTasks()
        .map { taskList ->
            taskList.map { listTaskDbModel ->
                listTaskDbModel.mapToDomainModel(cache.getCurrentUserId())
            }
        }
        .map { taskList ->
            taskList.filter { it.taskCategories.any { category -> category.id == taskId } }
        }
}

More generally, if you can do a filter in the DB query, it’s likely faster… You may get a lot of data back if you don’t filter it at the source, which will cause more data to need to be sent through the network, parsed and loaded in memory. If this is a lot, it will also cause more work for the garbage collector. As a rule of thumb, I’d try to do most of the filtering at the DB level unless it’s hard to do so or if the data is tiny and expected to remain so.

Answered By – Dici

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published