Home > Mobile >  Is there a better/faster way to insert data to a database from an external api in Laravel?
Is there a better/faster way to insert data to a database from an external api in Laravel?

Time:01-07

I am currently getting data from an external API for use my in Laravel API. I have everything working but I feel like it is slow.

I'm getting the data from the API with Http:get('url) and that works fast. It is only when I start looping through the data and making edits when things are slowing down.

I don't need all the data, but it would still be nice to edit before entering the data to the database as things aren't very consitent if possible. I also have a few columns that use data and some logic to make new columns so that each app/site doesn't need to do it.

I am saving to the database on each foreach loop with the eloquent Model:updateOrCreate() method which works but these json files can easily be 6000 lines long or more so it obviously takes time to loop through each set modify values and then save to the database each time. There usually isn't more than 200 or so entries but it still takes time. Will probably eventually update this to the new upset() method to make less queries to the database. Running in my localhost it is currently take about a minute and a half to run, which just seams way too long.

Here is a shortened version of how I was looping through the data.

$json = json_decode($contents, true);       
$features = $json['features'];

foreach ($features as $feature){
    
    // Get ID
    $id = $feature['id'];

    // Get primary condition data
    $geometry = $feature['geometry'];
    $properties = $feature['properties'];
    
    // Get secondary geometry data
    $geometryType = $geometry['type'];
    $coordinates = $geometry['coordinates'];


    Model::updateOrCreate(
    [
        'id' => $id,
    ],
    [
        'coordinates' => $coordinates,
        'geometry_type' => $geometryType,                    
    ]);
}

Most of what I'm doing behind the scenes to the data before going into the database is cleaning up some text strings but there are a few logic things to normalize or prep the data for websites and apps.

Is there a more efficient way to get the same result? This will ultimately be used in a scheduler and run on an interval.

Example Data structure from API documentation

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "additionalProperties": false,
  "properties": {
    "features": {
      "items": {
        "additionalProperties": false,
        "properties": {
          "attributes": {
            "type": [
              "object",
              "null"
            ]
          },
          "geometry": {
            "additionalProperties": false,
            "properties": {
              "coordinates": {
                "items": {
                  "items": {
                    "type": "number"
                  },
                  "type": "array"
                },
                "type": "array"
              },
              "type": {
                "type": "string"
              }
            },
            "required": [
              "coordinates",
              "type"
            ],
            "type": "object"
          },
          "properties": {
            "additionalProperties": false,
            "properties": {
              "currentConditions": {
                "items": {
                  "properties": {
                    "additionalData": {
                      "type": "string"
                    },
                    "conditionDescription": {
                      "type": "string"
                    },
                    "conditionId": {
                      "type": "integer"
                    },
                    "confirmationTime": {
                      "type": "integer"
                    },
                    "confirmationUserName": {
                      "type": "string"
                    },
                    "endTime": {
                      "type": "integer"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "sourceType": {
                      "type": "string"
                    },
                    "startTime": {
                      "type": "integer"
                    },
                    "updateTime": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "id",
                    "userName",
                    "updateTime",
                    "startTime",
                    "conditionId",
                    "conditionDescription",
                    "confirmationUserName",
                    "confirmationTime",
                    "sourceType",
                    "endTime"
                  ],
                  "type": "object"
                },
                "type": "array"
              },
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "nameId": {
                "type": "string"
              },
              "parentAreaId": {
                "type": "integer"
              },
              "parentSubAreaId": {
                "type": "integer"
              },
              "primaryLatitude": {
                "type": "number"
              },
              "primaryLongitude": {
                "type": "number"
              },
              "primaryMP": {
                "type": "number"
              },
              "routeId": {
                "type": "integer"
              },
              "routeName": {
                "type": "string"
              },
              "routeSegmentIndex": {
                "type": "integer"
              },
              "secondaryLatitude": {
                "type": "number"
              },
              "secondaryLongitude": {
                "type": "number"
              },
              "secondaryMP": {
                "type": "number"
              },
              "sortOrder": {
                "type": "integer"
              }
            },
            "required": [
              "id",
              "name",
              "nameId",
              "routeId",
              "routeName",
              "primaryMP",
              "secondaryMP",
              "primaryLatitude",
              "primaryLongitude",
              "secondaryLatitude",
              "secondaryLongitude",
              "sortOrder",
              "parentAreaId",
              "parentSubAreaId",
              "routeSegmentIndex",
              "currentConditions"
            ],
            "type": "object"
          },
          "type": {
            "type": "string"
          }
        },
        "required": [
          "type",
          "geometry",
          "properties",
          "attributes"
        ],
        "type": "object"
      },
      "type": "array"
    },
    "type": {
      "type": "string"
    }
  },
  "required": [
    "type",
    "features"
  ],
  "type": "object"
}

Second, related question.

Since this is being updated on an interval I have it updating and creating records from the json data, but is there an efficient way to delete old records that are no longer in the json file? I currently get an array of current ids and compare them to the new ids and then loop through each and delete them. There has to be a better way.

CodePudding user response:

Have no idea what to say to your first question, but I think you may try to do something like this regarding the second question.

SomeModel::query()->whereNotIn('id', $newIds)->delete();

$newIds you can collect during the first loop.

  • Related