Search code examples
arraysjsonrecordvapor

Insert multiple records into database with Vapor3


I want to be able to bulk add records to a nosql database in Vapor 3.

This is my Struct.

struct Country: Content {

   let countryName: String
   let timezone: String
   let defaultPickupLocation: String

}

So I'm trying to pass an array of JSON objects but I'm not sure how to structure the route nor how to access the array to decode each one.

I have tried this route:

    let countryGroup = router.grouped("api/country")

    countryGroup.post([Country.self], at:"bulk", use: bulkAddCountries)

with this function:

 func bulkAddCountries(req: Request, countries:[Country]) throws ->  Future<String> {
    for country in countries{
    return try req.content.decode(Country.self).map(to: String.self) { countries in



        //creates a JSON encoder to encode the JSON data
        let encoder = JSONEncoder()
        let countryData:Data
        do{
            countryData = try encoder.encode(country) // encode the data
        } catch {
            return "Error. Data in the wrong format."
        }
        // code to save data
    }
    }
}

So how do I structure both the Route and the function to get access to each country?


Solution

  • I'm not sure which NoSQL database you plan on using, but the current beta versions of MongoKitten 5 and Meow 2.0 make this pretty easy.

    Please note how we didn't write documentation for these two libraries yet as we pushed to a stable API first. The following code is roughly what you need with MongoKitten 5:

    // Register MongoKitten to Vapor's Services
    services.register(Future<MongoKitten.Database>.self) { container in
        return try MongoKitten.Database.connect(settings: ConnectionSettings("mongodb://localhost/my-db"), on: container.eventLoop)
    }
    
    // Globally, add this so that the above code can register MongoKitten to Vapor's Services
    extension Future: Service where T == MongoKitten.Database {}
    
    // An adaptation of your function
    func bulkAddCountries(req: Request, countries:[Country]) throws ->  Future<Response> {
        // Get a handle to MongoDB
        let database = req.make(Future<MongoKitten.Database>.self)
    
        // Make a `Document` for each Country
        let documents = try countries.map { country in
            return try BSONEncoder().encode(country)
        }
    
        // Insert the countries to the "countries" MongoDB collection
        return database["countries"].insert(documents: documents).map { success in
            return // Return a successful response
        }
    }