-1

I've tried to declare data entities for my mongo db and all I got is a null in a nested (via reference) collection.

That's what I want to see:

  1. mongodb document reference
  2. similar in spring
  3. raw DBRef (manually filled using mongo db compass)

My tries represented in this repository.

That's what I got (in all 3 cases)

frynet
  • 1
  • 2

1 Answers1

0

You are not joining the two collections.

See: https://micronaut-projects.github.io/micronaut-data/latest/guide/#mongoJoinQueries

Note the @Join can also go on the repository class.

@MongoRepository(databaseName = "test")
@Join("bananas-1")
interface FruitRepoV1 : CrudRepository<FruitV1, String>

UPDATE:

Fruit class and repository

@MappedEntity
data class Fruit(
    val name: String,
    @Relation(value = Relation.Kind.ONE_TO_MANY, mappedBy = "fruit")
    //mappedBy refers to Banana::fruit property not the MongoDB collection
    val bananas: MutableSet<Banana> = mutableSetOf()
) {
    @field:Id
    @GeneratedValue(GeneratedValue.Type.IDENTITY)
    var id: String = ""
}

@MongoRepository
@Join("bananas.fruit")
// with collection need to state the property in Fruit
// and then the property in the concrete class "Banana" to join on
interface FruitRepository : CrudRepository<Fruit, String> {
    override fun findAll() : List<Fruit>
    fun updateNameById(@Id id : String, name : String)
}

Banana class and repository

@MappedEntity
data class Banana(
    val name: String,
    @Relation(Relation.Kind.MANY_TO_ONE)
    val fruit: Fruit
) {
    @field:Id
    @GeneratedValue(GeneratedValue.Type.IDENTITY)
    var id: String = ""
}

@MongoRepository
interface BananaRepository : CrudRepository<Banana, String> {
    override fun findAll(): List<Banana>
    fun findByFruitName(name : String) : List<Banana>
}

Test case

@MicronautTest
class FruitTests (
    private val fruitRepository: FruitRepository,
    private val bananaRepository: BananaRepository) : StringSpec({

    "tests" {
        val fruitBowl = Fruit("bowl of bananas")

        fruitRepository.save(fruitBowl)

        bananaRepository.save(Banana("1", fruitBowl))
        bananaRepository.save(Banana("2", fruitBowl))
        bananaRepository.save(Banana("3", fruitBowl))

        val fruits = fruitRepository.findAll()
        fruits.count() shouldBe 1

        val fruit = fruits.first()
        fruit.name shouldBe "bowl of bananas"
        fruit.bananas.size shouldBe 3

        bananaRepository.findByFruitName("bowl of bananas").size shouldBe 3

        fruitRepository.updateNameById(fruit.id, "bananas")

        fruitRepository.findById(fruit.id).get().name shouldBe "bananas"

        bananaRepository.findByFruitName("bananas").size shouldBe 3
    }

})

Update 2:

@MappedEntity
data class Student(
    @field:Id
    @GeneratedValue(GeneratedValue.Type.IDENTITY)
    val id: String?,
    val name: String,
    @Relation(value = Relation.Kind.MANY_TO_MANY, cascade = [Relation.Cascade.PERSIST])
    val courses : List<Course>
) {
    constructor(name: String, courses: List<Course>) : this(null, name, courses)
}

@MongoRepository
@Join("courses")
interface StudentRepository : CrudRepository<Student, String>

@MappedEntity
data class Course(
    @field:Id
    @GeneratedValue(GeneratedValue.Type.IDENTITY)
    val id: String?,
    val name: String
) {
    constructor(name: String) : this(null, name)
}

@MongoRepository
interface CourseRepository : CrudRepository<Course, String>

Test

@MicronautTest
class StudentTests(
    private val studentRepository: StudentRepository,
    private val courseRepository: CourseRepository
) : StringSpec( {

    "tests" {
        courseRepository.count() shouldBe 0

        studentRepository.save(
            Student("me",
                listOf(
                    Course("Micronaut"),
                    Course("MongoDB"))
            )
        )

        val students = studentRepository.findAll()
        students.count() shouldBe 1
        println(students)

        val student = students.first()
        println(student)
        student.name shouldBe "me"
        student.courses.size shouldBe 2

        courseRepository.count() shouldBe 2

    }
})
ShingJo
  • 614
  • 1
  • 7
  • `Unable to implement Repository method: FruitRepoV1.findById(Object id). Invalid join spec [bananas-1]. Property is not an association!` I've already tried `@Join("bananas")` for all 3 cases and still getting `null` :( – frynet Jan 05 '23 at 03:33
  • The `@Join("bananas-1")` was just an example of a join on the class and not the method. Probably should have used something not in your example. Updated the answer with a full example. – ShingJo Jan 06 '23 at 22:30
  • Idk how u got passed tests :D. Bananas array in mongo db still equals `null`. For viewing I'm using [mongodb compass](https://www.mongodb.com/products/compass) . Can u try to write to local-hosted db (not with micronaut test resources) and send me a screenshot? – frynet Jan 08 '23 at 05:20
  • For the above fruit example, it would be. The bananas aren't being added directly to the Fruit. Taken from your V1 example. Added another example. – ShingJo Jan 08 '23 at 16:53
  • [Your edition](https://github.com/frynet/MicronautFailedMappingMongoNestedEntities/tree/ShingJo_edition) still doesn't looks like what I need :D. Look the [result](https://i.stack.imgur.com/ePHi9.png). – frynet Jan 09 '23 at 04:57