Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eloquent Eager Loading in Cursor (Lazy Collection)

I'm trying to export a large number of records from my database, but I need relationship data in order to build the export correctly. Ideally I would be able to use cursor() to get a Lazy Collection, but that won't load the relationships. I can't load the relationship within a loop, because that will create N+1 queries, and this could be hundreds of thousands of additional queries, which is unacceptable.

Here's what "works" (but runs out of memory):

Record::with('projects')->get()->map(function ($record) {
  dd($record); // Shows the `projects` relationship
});

But when I use cursor()...

Record::with('projects')->cursor()->map(function ($record) {
  dd($record); // Does NOT show the `projects` relationship
});

Is there a way to get a lazy collection that includes a record's relationship? I have looked in the documentation and it's not clear. Other suggestions have been to use chunk() which is unfortunately not a possibility in this situation.

EDIT: I shouldn't say chunk isn't a possibility, but it's a very expensive re-write. Currently, the data is structured with a lot of variability. So in order to construct the CSV for export, I need (for example) a header for the file. I currently grab that header by looping through all the records (the fields are stored in a JSONB field) and building out an array based on the fields present on those records.

I am also normalizing the data against those headers. So if one record has the field "address-1" but another record doesn't have that, the one that doesn't have it instead shows a blank value in the appropriate column. Otherwise, when inserting the row into the CSV, it doesn't respect the header.

These operations currently grab the entire data set and use a LazyCollection to map the header and normalize the records, and then feed it into the CSV one at a time. It would be ideal if I could grab relationships in a LazyCollection as well rather than having to rewrite the workflow.

like image 240
Caleb Anthony Avatar asked Sep 05 '25 02:09

Caleb Anthony


1 Answers

according to this doc

cursor work in db stage, while loading relations come after method 'get' or 'first' ...

so: the code in cursor will work in db row represented as Model instance before the overall result, means that this code will run into db, without loading the relation, again db row (iterate through your database records...)

if you can't use chunk... then i think that you can use mySql to manage your data using raw-expressions

like image 132
OMR Avatar answered Sep 08 '25 22:09

OMR