Search code examples
databasemongodbkotlinktor

MongoDB Leaves Out One Single Field From JSON Objects?


I'm trying to build a Garden Plants API using KTOR as the backend for the HTTP responses. So far it has been working really well, but I found a small, yet huge issue with my database and MongoDB that I can just not figure out.

I was inserting a bunch of plants into this database through my add-plant route, and it gets added to MongoDB programmatically successfully. Upon trying to retrieve the plant data, I get the error in the console of my API program that isSpeciesOrVariety does not have a value or does not exist, but it should always have a value: either "Species" or "Variety". I checked inside of MongoDB compass, and everything I inserted is there, but every entry is missing this one singular field (isSpeciesOrVariety). It seem like such a hassle to just add these fields manually, and I want them all to be automatic, but this is preventing that whole automation task.

I'm pretty new to using MongoDB and have never encountered anything like this. Is this just a bug with Mongo, or is it something I'm doing wrong?

What I have tried: I have put in my class file for the JSON object @SerialName("isSpeciesOrVariety"), And this does not work. Here is the code for that Kotlin class:

@Serializable
data class PlantSpeciesDetails(
val apiId: Int,
val averageHeight: AverageHeight,
val averageSpread: AverageSpread,
val name: String,
val description: String,
val floweringMonths: List<String>,
val floweringSeason: String,
val fruitIsEdible: Boolean,
val growingCycle: String,
val growthRate: Int,
val hardinessZones: HardinessZones,
val harvestMonths: List<String>,
val harvestSeason: String,
val harvestingGuide: String,
val hasFlowers: Boolean,
val hasSeeds: Boolean,
val images: List<Image>,
val isContainerFriendly: Boolean,
val isFrostTolerant: Boolean,
val isHeatTolerant: Boolean,
val isIndoorFriendly: Boolean,
val isMedicinal: Boolean,
val isPoisonousToHumans: Boolean,
val isPoisonousToPets: Boolean,
val isSaltTolerant: Boolean,
@SerialName("isSpeciesOrVariety")
val isSpeciesOrVariety: String,
val leavesAreEdible: Boolean,
val maintenanceLevel: Int,
val maturityTime: MaturityTime,
val otherNames: List<String>,
val plantSpacing: PlantSpacing,
val plantingMonths: List<String>,
val plantingSeason: String,
val preferredSoil: List<String>,
val preferredSunlight: List<String>,
val pruningGuide: String,
val scientificName: String,
val seedGerminationTime: SeedGerminationTime,
val seedsAreEdible: Boolean,
val soilPh: String,
val sowingGuide: String,
val wateringGuide: String
)

I have printed out the resulting class after the plant is received from the client (right before it is added to the database) and the isSpeciesOrVariety field is correct. Upon insertion, the database just leaves it out for some reason.

It is not the retrieval from the database that isn't working, as the data is not in the database, and when added manually, it is retrieved successfully with the correct data.

Here are the functions that are in charge of inserting:

Get from client end point:

route("/add-plant"){
    post{
        val request = try {
            call.receive<PlantSpeciesDetails>()
        } catch (e: ContentTransformationException){
            call.respond(HttpStatusCode.BadRequest)
            return@post
        }

        if(createOrUpdatePlant(request)){
            call.respond(
                HttpStatusCode.OK,
                "Plant added or updated successfully"
            )
        } else {
            call.respond(
                HttpStatusCode.Conflict
            )
        }
    }
}

Insert:

suspend fun createOrUpdatePlant(plant: PlantSpeciesDetails): Boolean{
    val filter = eq("apiId", plant.apiId)
    print(plant) // Find out if the field is actually correct here, and it is!
    val result = plants.replaceOne(
        filter,
        plant,
        ReplaceOptions().upsert(true)
    )

    return result.wasAcknowledged()
}

Does my code have something to do with this?


Solution

  • @artioni in the comments found the solution.

    Just an assumption, can't be the issue be related to filed name, I refer that is starting with is which in Java is considered getter for boolean field while here you have a String?

    The first field with the keyword is within it gets confused with the actual keyword. By simply changing the fields to exclude is, then all data is added to the database correctly.

    EDIT: Doing a bit of research helped me understand valid keys in JSON:

    Do not use the reserved keywords that are generally used in programming languages. They can lead to unexpected behavior.

    In which is is a common reserved keyword in many programming languages.