package mongo import ( Mongomaster "api-poliklinik/pkg/models/mongo/master/masteraddress" "context" "fmt" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" "log" "strings" "time" ) func (s *DatabaseService) InsertState(req Mongomaster.State) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() _, err := s.DBMongo.Collection("state").InsertOne(ctx, req) if err != nil { log.Println(err) return err } return nil } func (s *DatabaseService) InsertCity(req Mongomaster.City) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() _, err := s.DBMongo.Collection("city").InsertOne(ctx, req) if err != nil { log.Println(err) return err } return nil } func (s *DatabaseService) InsertDistrict(req Mongomaster.District) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() _, err := s.DBMongo.Collection("district").InsertOne(ctx, req) if err != nil { log.Println(err) return err } return nil } func (s *DatabaseService) InsertVillage(req Mongomaster.Village) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() _, err := s.DBMongo.Collection("village").InsertOne(ctx, req) if err != nil { log.Println(err) return err } return nil } func (s *DatabaseService) Getsmf() ([]*Mongomaster.Smfmongo, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() datasmf, err := s.DBMongo.Collection("smf").Find(ctx, bson.D{}) if err != nil { log.Println(err) } var smf []*Mongomaster.Smfmongo err = datasmf.All(ctx, &smf) if err != nil { log.Println(err) return nil, err } return smf, nil } func (s *DatabaseService) GetICD(limit int64, skip int64) ([]*Mongomaster.Icdmongo, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() findOptions := options.Find() findOptions.SetLimit(limit) findOptions.SetSkip(skip) filter := bson.M{ "status": "active", } dataICD, err := s.DBMongo.Collection("icd").Find(ctx, filter, findOptions) if err != nil { log.Println(err) } var ICD []*Mongomaster.Icdmongo err = dataICD.All(ctx, &ICD) if err != nil { log.Println(err) return nil, err } return ICD, nil } func (s *DatabaseService) Getdataprovinsi() ([]*Mongomaster.State, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() dataprovinsi, err := s.DBMongo.Collection("state").Find(ctx, bson.D{}) if err != nil { log.Println(err) } var provinsi []*Mongomaster.State err = dataprovinsi.All(ctx, &provinsi) if err != nil { log.Println(err) return nil, err } return provinsi, nil } func (s *DatabaseService) Getdatakota() ([]*Mongomaster.City, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() datakota, err := s.DBMongo.Collection("city").Find(ctx, bson.D{}) if err != nil { log.Println(err) } var kota []*Mongomaster.City err = datakota.All(ctx, &kota) if err != nil { log.Println(err) return nil, err } return kota, nil } func (s *DatabaseService) Getdatakecamatan() ([]*Mongomaster.District, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() datakecamatan, err := s.DBMongo.Collection("district").Find(ctx, bson.D{}) if err != nil { log.Println(err) } var kecamatan []*Mongomaster.District err = datakecamatan.All(ctx, &kecamatan) if err != nil { log.Println(err) return nil, err } return kecamatan, nil } func (s *DatabaseService) Getdatakelurahan(name string) ([]*Mongomaster.Village, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() filter := bson.M{ "name": name, } datakelurahan, err := s.DBMongo.Collection("village").Find(ctx, filter) if err != nil { log.Println(err) } var kelurahan []*Mongomaster.Village err = datakelurahan.All(ctx, &kelurahan) if err != nil { log.Println(err) return nil, err } return kelurahan, nil } func (s *DatabaseService) SearchKelurahan(query string) ([]*Mongomaster.Village, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // Buat regex pattern untuk pencarian case-insensitive regex := primitive.Regex{Pattern: query, Options: "i"} // Buat filter untuk pencarian berdasarkan nama filter := bson.M{ "name": regex, } // Cari kelurahan yang cocok, batasi 10 hasil opts := options.Find().SetLimit(10) cursor, err := s.DBMongo.Collection("village").Find(ctx, filter, opts) if err != nil { log.Println(err) return nil, err } // Decode hasil query ke dalam slice struct var kelurahanList []*Mongomaster.Village if err = cursor.All(ctx, &kelurahanList); err != nil { log.Println(err) return nil, err } return kelurahanList, nil } func (s *DatabaseService) GetHierarchyByKelurahan(kelurahanId string) (map[string]interface{}, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // 1. Cari data kelurahan berdasarkan identifier[0].value filter := bson.M{ "identifier.0.value": kelurahanId, } log.Printf("Mencari kelurahan dengan filter: %v", filter) var kelurahan Mongomaster.Village err := s.DBMongo.Collection("village").FindOne(ctx, filter).Decode(&kelurahan) if err != nil { log.Println("Error saat mencari kelurahan:", err) return nil, err } log.Printf("Kelurahan ditemukan: %s, reference kecamatan: %s", kelurahan.Name, kelurahan.District.Reference) // 2. Ekstrak ID kecamatan dari referensi // PENTING: Periksa format referensi yang sebenarnya districtRef := kelurahan.District.Reference var districtId string // Coba berbagai format yang mungkin if strings.HasPrefix(districtRef, "distric/") { districtId = strings.Replace(districtRef, "distric/", "", 1) } else if strings.HasPrefix(districtRef, "district/") { districtId = strings.Replace(districtRef, "district/", "", 1) } else { // Jika format lain, ambil bagian setelah "/" parts := strings.Split(districtRef, "/") if len(parts) > 1 { districtId = parts[1] } else { districtId = districtRef // Gunakan seluruh string jika tidak ada "/" } } log.Printf("ID kecamatan yang diekstrak: %s", districtId) // 3. Cari data kecamatan berdasarkan identifier.value // Coba beberapa kemungkinan filter var kecamatan Mongomaster.District var kecamatanErr error // Coba dengan exact match pada identifier.value kecamatanFilter1 := bson.M{ "identifier.0.value": districtId, } log.Printf("Mencoba filter kecamatan 1: %v", kecamatanFilter1) kecamatanErr = s.DBMongo.Collection("district").FindOne(ctx, kecamatanFilter1).Decode(&kecamatan) // Jika masih error, coba dengan _id if kecamatanErr != nil { log.Printf("Filter 1 gagal: %v, mencoba filter 2", kecamatanErr) kecamatanFilter2 := bson.M{ "_id": districtId, } kecamatanErr = s.DBMongo.Collection("district").FindOne(ctx, kecamatanFilter2).Decode(&kecamatan) } // Jika masih error, coba dengan regex search pada name if kecamatanErr != nil { log.Printf("Filter 2 gagal: %v, mencoba filter berdasarkan display name", kecamatanErr) kecamatanFilter3 := bson.M{ "name": kelurahan.District.Display, } kecamatanErr = s.DBMongo.Collection("district").FindOne(ctx, kecamatanFilter3).Decode(&kecamatan) } // Jika semua filter gagal if kecamatanErr != nil { log.Println("Error saat mencari kecamatan dengan semua filter:", kecamatanErr) // Tampilkan semua kecamatan untuk debugging debugCursor, debugErr := s.DBMongo.Collection("district").Find(ctx, bson.M{}) if debugErr == nil { var allDistricts []Mongomaster.District debugErr = debugCursor.All(ctx, &allDistricts) if debugErr == nil { log.Printf("Daftar semua kecamatan (sampel 3): %+v", allDistricts[:min(3, len(allDistricts))]) } } return nil, kecamatanErr } log.Printf("Kecamatan ditemukan: %s, reference kota: %s", kecamatan.Name, kecamatan.City.Reference) // 4. Ekstrak ID kota dari referensi (dengan pendekatan yang sama) cityRef := kecamatan.City.Reference var cityId string if strings.HasPrefix(cityRef, "city/") { cityId = strings.Replace(cityRef, "city/", "", 1) } else { parts := strings.Split(cityRef, "/") if len(parts) > 1 { cityId = parts[1] } else { cityId = cityRef } } log.Printf("ID kota yang diekstrak: %s", cityId) // 5. Cari data kota kotaFilter := bson.M{ "identifier.0.value": cityId, } var kota Mongomaster.City err = s.DBMongo.Collection("city").FindOne(ctx, kotaFilter).Decode(&kota) if err != nil { log.Println("Error saat mencari kota:", err) return nil, err } log.Printf("Kota ditemukan: %s, reference provinsi: %s", kota.Name, kota.State.Reference) // 6. Ekstrak ID provinsi stateRef := kota.State.Reference var stateId string if strings.HasPrefix(stateRef, "provinsi/") { stateId = strings.Replace(stateRef, "provinsi/", "", 1) } else { parts := strings.Split(stateRef, "/") if len(parts) > 1 { stateId = parts[1] } else { stateId = stateRef } } log.Printf("ID provinsi yang diekstrak: %s", stateId) // 7. Cari data provinsi provinsiFilter := bson.M{ "identifier.0.value": stateId, } var provinsi Mongomaster.State err = s.DBMongo.Collection("state").FindOne(ctx, provinsiFilter).Decode(&provinsi) if err != nil { log.Println("Error saat mencari provinsi:", err) return nil, err } log.Printf("Provinsi ditemukan: %s", provinsi.Name) // 8. Buat respons dengan data lengkap hierarchy := map[string]interface{}{ "kecamatan": map[string]interface{}{ "id": kecamatan.Identifier[0].Value, "name": kecamatan.Name, }, "kelurahan": map[string]interface{}{ "id": kelurahan.Identifier[0].Value, "name": kelurahan.Name, }, "kota": map[string]interface{}{ "id": kota.Identifier[0].Value, "name": kota.Name, }, "provinsi": map[string]interface{}{ "id": provinsi.Identifier[0].Value, "name": provinsi.Name, }, } return hierarchy, nil } // Helper function untuk min func min(a, b int) int { if a < b { return a } return b } func (s *DatabaseService) GetHierarchyFromProvinsi(provinsiId string) (map[string]interface{}, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // 1. Ambil data provinsi var provinsi Mongomaster.State provinsiFilter := bson.M{ "identifier.0.value": provinsiId, } err := s.DBMongo.Collection("state").FindOne(ctx, provinsiFilter).Decode(&provinsi) if err != nil { log.Println("Error saat mencari provinsi:", err) return nil, err } log.Printf("Provinsi ditemukan: %s", provinsi.Name) // DEBUGGING: Tampilkan struktur data kota // Ambil semua kota tanpa filter untuk memeriksa struktur data allCitiesCursor, err := s.DBMongo.Collection("city").Find(ctx, bson.M{}) if err != nil { log.Println("Error saat mengambil semua kota:", err) return nil, err } var allCities []Mongomaster.City if err = allCitiesCursor.All(ctx, &allCities); err != nil { log.Println("Error saat decode semua kota:", err) return nil, err } log.Printf("Total kota di database: %d", len(allCities)) // Periksa dan tampilkan format referensi di 3 kota pertama for i, city := range allCities { if i < 3 { log.Printf("Kota: %s, State Reference: %+v", city.Name, city.State.Reference) } } // Cari kota berdasarkan provinsi setelah melihat format referensi yang benar var kotaList []map[string]interface{} // Coba berbagai kemungkinan filter filters := []bson.M{ {"state.reference": "provinsi/" + provinsiId}, {"state.reference": provinsiId}, {"state.display": provinsi.Name}, } var kota []Mongomaster.City var foundFilter string for _, filter := range filters { log.Printf("Mencoba filter kota: %v", filter) kotaCursor, _ := s.DBMongo.Collection("city").Find(ctx, filter) var tempKota []Mongomaster.City if kotaCursor.All(ctx, &tempKota) == nil && len(tempKota) > 0 { kota = tempKota foundFilter = fmt.Sprintf("%v", filter) log.Printf("Filter yang berhasil: %s, menemukan %d kota", foundFilter, len(kota)) break } } // Jika semua filter gagal, gunakan pendekatan alternatif: manual matching if len(kota) == 0 { log.Println("Semua filter gagal, mencoba pendekatan manual matching") // Cari kota yang memiliki referensi ke provinsi ini dengan cara apa pun for _, city := range allCities { stateRef := city.State.Reference stateDisplay := city.State.Display // Cek apakah referensi atau display cocok dengan provinsi if strings.Contains(stateRef, provinsiId) || strings.EqualFold(stateDisplay, provinsi.Name) { kota = append(kota, city) } } log.Printf("Pendekatan manual menemukan %d kota", len(kota)) } // Transform data kota kotaList = make([]map[string]interface{}, 0) for _, k := range kota { kotaId := k.Identifier[0].Value log.Printf("Memproses kota: %s (ID: %s)", k.Name, kotaId) kotaItem := map[string]interface{}{ "id": kotaId, "name": k.Name, "kecamatan": []map[string]interface{}{}, } // DEBUGGING: Tampilkan struktur data kecamatan allDistrictsCursor, _ := s.DBMongo.Collection("district").Find(ctx, bson.M{}) var allDistricts []Mongomaster.District if allDistrictsCursor.All(ctx, &allDistricts) == nil { log.Printf("Total kecamatan di database: %d", len(allDistricts)) // Periksa kecamatan yang memiliki referensi ke kota ini var kecamatanForCity []Mongomaster.District for _, district := range allDistricts { cityRef := district.City.Reference cityDisplay := district.City.Display // Cek apakah referensi atau display cocok dengan kota if strings.Contains(cityRef, kotaId) || strings.EqualFold(cityDisplay, k.Name) { kecamatanForCity = append(kecamatanForCity, district) } } log.Printf("Menemukan %d kecamatan untuk kota %s", len(kecamatanForCity), k.Name) // Proses kecamatan yang ditemukan kecamatanList := make([]map[string]interface{}, 0) for _, kec := range kecamatanForCity { kecamatanId := kec.Identifier[0].Value log.Printf("Memproses kecamatan: %s (ID: %s)", kec.Name, kecamatanId) kecamatanItem := map[string]interface{}{ "id": kecamatanId, "name": kec.Name, "kelurahan": []map[string]interface{}{}, } // DEBUGGING: Tampilkan struktur data kelurahan allVillagesCursor, _ := s.DBMongo.Collection("village").Find(ctx, bson.M{}) var allVillages []Mongomaster.Village if allVillagesCursor.All(ctx, &allVillages) == nil { log.Printf("Total kelurahan di database: %d", len(allVillages)) // Periksa kelurahan yang memiliki referensi ke kecamatan ini var kelurahanForDistrict []Mongomaster.Village for _, village := range allVillages { districtRef := village.District.Reference districtDisplay := village.District.Display // Cek apakah referensi atau display cocok dengan kecamatan if strings.Contains(districtRef, kecamatanId) || strings.EqualFold(districtDisplay, kec.Name) { kelurahanForDistrict = append(kelurahanForDistrict, village) } } log.Printf("Menemukan %d kelurahan untuk kecamatan %s", len(kelurahanForDistrict), kec.Name) // Proses kelurahan yang ditemukan kelurahanList := make([]map[string]interface{}, 0) for _, kel := range kelurahanForDistrict { kelurahanItem := map[string]interface{}{ "id": kel.Identifier[0].Value, "name": kel.Name, } kelurahanList = append(kelurahanList, kelurahanItem) } // Tambahkan kelurahan ke kecamatan kecamatanItem["kelurahan"] = kelurahanList } kecamatanList = append(kecamatanList, kecamatanItem) } // Tambahkan kecamatan ke kota kotaItem["kecamatan"] = kecamatanList } kotaList = append(kotaList, kotaItem) } // Buat response hierarki hierarchy := map[string]interface{}{ "provinsi": map[string]interface{}{ "id": provinsi.Identifier[0].Value, "name": provinsi.Name, "kota": kotaList, }, } return hierarchy, nil }