Migration not starting with mongock 4.3.8 - mongodb

I am trying to create indexes on a mongodb collection using mongock version 4.3.8. The mongockLock and mongockChangeLog collections are eventually created, but the migration itself does not run. mongockChangeLog table is empty. Query db.BOOKS.getIndexes(); returns a single string: with an index for id (the value of name in it is equal to _id_), which is most likely generated automatically. There are no obvious errors in the logs either.
Everything else seems to be set up correctly, I don't understand why my migration is not running.
build.gradle.kts:
implementation("com.github.cloudyrock.mongock:mongodb-springdata-v3-driver:4.3.8")
implementation("com.github.cloudyrock.mongock:mongock-spring-v5:4.3.8")
implementation(platform("com.github.cloudyrock.mongock:mongock-bom:4.3.8"))
application.yml:
mongock:
change-logs-scan-package:
- com.dreamland.configuration.migration
config file:
#EnableMongock
#Configuration
#EnableMongoAuditing
class MongoConfig
Migration file:
#ChangeLog(order = "1668471203")
class IndexChangeLog {
companion object : KLogging()
#ChangeSet(order = "1668471204", id = "1668471204_create_indexes", author = "Irish")
fun createIndexes(mongockTemplate: MongockTemplate) {
val indexOps = mongockTemplate.indexOps(BookObjectDocument::class.java)
Index().on("createdAt", Sort.Direction.DESC).let { indexOps.ensureIndex(it) }.also { log(it) }
Index().on("createdBy", Sort.Direction.ASC).let { indexOps.ensureIndex(it) }.also { log(it) }
Index().on("type", Sort.Direction.DESC).let { indexOps.ensureIndex(it) }.also { log(it) }
}
private fun log(indexName: String) {
logger.info { "Index '$indexName' was created successfully" }
}
}
Document class:
#Document(collection = "BOOKS_V2")
data class BookObjectDocument(
val type: BookObjectType?,
val description: String?
) {
#Id
lateinit var id: String
#CreatedDate
lateinit var createdAt: Instant
#CreatedBy
var createdBy: String? = null
}

Related

LIveData is observed more than twice everytime from acivity and emitting previous data

I follow MVVM Login API, with Retrofit ,My problem is livedata is observed more than twice and always emitting previous response when observed from activity, But inside Repository its giving correct response
I tried a lot of solutions from stackoverflow and other websites but still no luck, Tried removing observers also but still getting previous data ,so plz suggest a working solution, I will post my code below,
LoginActivity.kt
private lateinit var loginViewModel: LoginViewModel
loginViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(
LoginViewModel::class.java
)
loginViewModel.login(userEmail, pwd)
loginViewModel.getLoginRepository().observe(this, Observer {
val loginResult = it ?: return#Observer
val accessToken = loginResult.user?.jwtToken.toString()
})
val statusMsgObserver = Observer<String> { statusMsg ->
showToast(statusMsg)
})
val errorMsgObserver = Observer<String> { errorMsg ->
// Update the UI
showToast(errorMsg)
})
loginViewModel.getStatusMessage()?.observe(this, statusMsgObserver)
loginViewModel.getErrorStatusMessage()?.observe(this, errorMsgObserver)
LoginViewModel.kt:
class LoginViewModel: ViewModel() {
private var loginRepository: LoginRepository? = null
private var _mutableLiveData = MutableLiveData<LoginAPIResponse?>()
val liveData: LiveData<LoginAPIResponse?> get() = _mutableLiveData
private var responseMsgLiveData:MutableLiveData<String>?= null
private var errorResponseMsgLiveData:MutableLiveData<String>?= null
fun login(username: String, password: String) {
loginRepository = LoginRepository.getInstance()!!
/* Query data from Repository */
//val _mutableLiveData: MutableLiveData<Response<LoginAPIResponse?>?>? = loginRepository?.doLogin(username, password)
_mutableLiveData = loginRepository?.doLogin(username, password)!!
responseMsgLiveData = loginRepository?.respMessage!!
errorResponseMsgLiveData = loginRepository?.loginResponseErrorData!!
}
fun getLoginRepository(): LiveData<LoginAPIResponse?> {
return liveData
}
fun getStatusMessage(): LiveData<String>? {
return responseMsgLiveData
}
fun getErrorStatusMessage(): LiveData<String>? {
return errorResponseMsgLiveData
}
}
LoginRepository.kt:
class LoginRepository {
private val loginApi: ApiEndpoints = RetrofitService.createService(ApiEndpoints::class.java)
val responseData = MutableLiveData<LoginAPIResponse?>()
var respMessage = MutableLiveData<String>()
var loginResponseErrorData = MutableLiveData<String>()
fun doLogin(username: String, password: String)
: MutableLiveData<LoginAPIResponse?> {
respMessage.value = null
loginResponseErrorData.value = null
val params = JsonObject()
params.addProperty("email", username)
params.addProperty("password",password)
val jsonParams = JsonObject()
jsonParams.add("user",params)
loginApi.loginToServer(jsonParams).enqueue(object : Callback<LoginAPIResponse?> {
override fun onResponse( call: Call<LoginAPIResponse?>, response: Response<LoginAPIResponse?> ) {
responseData.value = response.body()
respMessage.value = RetrofitService.handleError(response.code())
val error = response.errorBody()
if (!response.isSuccessful) {
val errorMsg = error?.charStream()?.readText()
println("Error Message: $errorMsg")
loginResponseErrorData.value = errorMsg
} else {
println("API Success -> Login, $username, ${response.body()?.user?.email.toString()}")
}
}
override fun onFailure(call: Call<LoginAPIResponse?>, t: Throwable) {
println("onFailure:(message) "+t.message)
loginResponseErrorData.value = t.message
responseData.value = null
}
})
return responseData
}
companion object {
private var loginRepository: LoginRepository? = null
internal fun getInstance(): LoginRepository? {
if (loginRepository == null) {
loginRepository = LoginRepository()
}
return loginRepository
}
}
}
In onDestroy(),I have removed the observers,
override fun onDestroy() {
super.onDestroy()
loginViewModel.getLoginRepository()?.removeObservers(this)
this.viewModelStore.clear()
}
In LoginActivity, when I observe loginResult it gives previous emitted accessToken first and then again called and giving current accessToken, Similarly observer is called more than twice everytime.
But inside repository,its giving recent data, plz check my code and suggest where I have to correct to get correct recent livedata
Finally i found the solution, In LoginRepository, I declared responseData outside doLogin(), It should be declared inside doLogin()
Since it was outside the method, it always gave previous data first and then current data,
Once I declare inside method problem was solved and now it is working Perfect!!!

Grails MongoDB Lists do not update, am I doing something wrong?

I am currently using Grails 2.5.4, with the MongoDB plugin (org.grails.plugins:mongodb:6.0.0.RC1) and whenever I try to update a List of any domain class, it doesn't work, example:
Votation class:
class Votation {
String question
int minVotes
List <VoteOption> options
User owner
Chat chat
static belongsTo = [chat: Chat]
static embedded = ['options']
static constraints = {
owner nullable: false
chat nullable: false
//question nullable: false
}
VoteOption class:
class VoteOption {
String option
String url
List <User> voters
static belongsTo = [chat: Chat]
}
When I try to update the list:
//some more code...
Votation votation = Votation.findById(votationId as Long)
VoteOption option = votation.options.find { it.option == votationOption }
User user = User.findOrCreateNew(params.user)
if (option.voters) {
option.voters.add(user) // THIS DOESN'T WORK!
}
else {
option.voters = [user] //This DOES work
}
This is just an example, I have 2 more domain classes that also have Lists, and they don't work either.
Restarting Grails does not fix this, and this also happens on the other developer's computer, so it's not my enviroment. Everything else is saved correctly
Try this
//some more code...
Votation votation = Votation.findById(votationId as Long)
VoteOption option = votation.options.find { it.option == votationOption }
User user = User.findOrCreateNew(params.user)
if (user) {
option.addToVoters(user) // <----
}
option.save(flush:true, failOnError:true)
Ref: http://docs.grails.org/2.1.0/ref/Domain%20Classes/addTo.html

Grails 3.0.9 not updating object with MongoDB

I've problems updating a domain class. I'm using Grails 3.0.9 and MongoDB (for Gorm 5.0.0.RC1)
In my build.gradle:
compile "org.grails.plugins:mongodb:5.0.0.RC1"
compile "org.mongodb:mongodb-driver:3.0.2"
compile "org.grails:grails-datastore-gorm-mongodb:5.0.0.RC1"
runtime 'org.springframework.data:spring-data-mongodb:1.8.1.RELEASE'
compile("org.grails:gorm-mongodb-spring-boot:5.0.0.RC1")
The test:
#Integration
class CompanyControllerIntegrationSpec extends Specification{
def grailsApplication
Company company
RestBuilder rest
def setupData() {
company = Company.buildWithoutSave().save(flush: true, failOnError: true)
}
def setup(){
rest = new RestBuilder()
}
def "test update a company" (){
def company2
given:
setupData()
def id = company.id
when:
RestResponse response = rest.put("http://localhost:${grailsApplication.config.server.port}/${company.companyKey}/company") {
json {
name = "newName"
description = "new Description"
}
}
company2 = Company.findById(id)
then:
response.status == 200
response.json.name == "newName"
company2.name == "newName"
company2.description == "new Description"
}
def cleanup() {
Company.collection.remove(new BasicDBObject())
}
}}
The controller:
class CompanyController extends ExceptionController{
static allowedMethods = ['update':'PUT','show':'GET',
'updateNew':'PUT','showNew':'GET']
CompanyService companyService
def update(String companyKey){
def object = request.JSON?request.JSON:params
Company companyOut = companyService.update(object, companyKey)
render text:companyOut as JSON, status:HttpStatus.OK
}
}
The service:
class CompanyService {
def securityService
def grailsApplication
public Company update(object, String companyKey) throws ForbiddenException, InvalidRequestException, NotFoundException{
Company company = findByKey(companyKey)
if (object.name!=null)
company.name = object.name
if (object.description!=null)
company.description = object.description
if (object.enterprise!=null)
company.enterprise = object.enterprise
if (object.genKey!=null)
company.companyKey = UUID.randomUUID().toString()
if (!company.save(flush:true)){
println company.errors
throw new InvalidRequestException("Some parameters are missing or are invalid: "+company.errors.fieldErrors.field)
}
return company
}
public Company findByKey(String companyKey) throws NotFoundException, ForbiddenException {
if (!companyKey){
throw new ForbiddenException("The company key has not been given")
}
Company company = Company.findByCompanyKey(companyKey)
if (!company){
throw new NotFoundException("No company exists for the given key")
}
return company
}
}
The results of the test are:
- response.status is 200
- response.json.name is "newName"
- company.name is old name ("company 1")
If I don't do the cleanup, the database still have the old value. I've followed the save method, also inside Mongo gorm classes, and I've seen that one problem is that the fields are not being marked as dirty, but don't know why.
With other Domain classes that are similar to this one, the update is done without problems and the properties are marked as dirty.

Variant type and non, with same name

i've tried to use typelite with entity framework and Identity framework.
in identity framework exists various types in the format TypeName<Tkey> and TypeName: TypeName<String>.
typelite correctly exports the types, but this behaviour is not possible in typescript, how should i work around that ?
Class:
namespace DTO
{
[TypeLite.TsClass]
public class Test : Test<String>
{
}
public class Test<TKey>
{
public TKey Id { get; set; }
public String Name { get; set; }
}
}
Configuration 1:
<# var ts = TypeScript.Definitions()
.WithReference("Enums.ts")
.ForLoadedAssemblies();
#>
Output 1, here the error is: Type 'Test<TKey>' recursively references itself as a base type.
declare module DTO {
interface Test extends DTO.Test<string> {
}
interface Test<TKey> {
Id: TKey;
Name: string;
}
}
Configuration 2:
<# var ts = TypeScript.Definitions()
.WithReference("Enums.ts")
.ForLoadedAssemblies()
.WithTypeFormatter((type, f) => "I" + ((TypeLite.TsModels.TsClass)type).Name);
#>
Output 2, here the variant Type got the I too and things got messed up badly
declare module DTO {
interface IUser {
Id: string;
Name: string;
Surname: string;
UserName: string;
Email: string;
Roles: string[];
}
interface ITest extends DTO.ITest {
}
interface ITest {
Id: ITKey;
Name: string;
}
}
If you have both generic and non-generic types with the same name, in the same namespace, you have to give them a slightly different name.
Change the model definition to:
var ts = TypeScript.Definitions()
.WithReference("Enums.ts")
.ForLoadedAssemblies();
ts.WithTypeFormatter((t, f) => GenerateTypeName(t, f, ts.ScriptGenerator));
Add this at the end:
<#+
private string GenerateTypeName(TsType tsType, ITsTypeFormatter f, TsGenerator gen)
{
TsClass tsClass = (TsClass) tsType;
string name = tsClass.Name;
if (!tsClass.GenericArguments.Any())
return name;
name += "_" + tsClass.GenericArguments.Count;
name += "<" + string.Join(",", tsClass.GenericArguments.Select(arg =>
{
string suffix = "";
var argCol = arg as TsCollection;
if (argCol != null)
{
suffix = string.Join("", Enumerable.Repeat("[]", argCol.Dimension));
}
return gen.GetFullyQualifiedTypeName(arg) + suffix;
})) + ">";
return name;
}
#>
It will generate:
declare module DTO {
interface ITest extends DTO.ITest_1<string> {
}
interface ITest_1<TKey> {
Id: TKey;
Value: string;
}
}

Update Mongo document field from Grails app

I have a requirement where I have to check in the database if the value of a boolean variable(crawled) is false. If so I have to set it to true. I am finding the record based on the value of a string variable(website). I referenced this link but it didn't help. Please tell me what I am doing wrong.
I tried this:
def p = Website.findByWebsite(website);
if(p['crawled'] == true) {
println "already crawled"
} else {
mongo.website.update( p, new BasicDBObject( '$set', new BasicDBObject( 'crawled', 'false' ) ) )
println "updated object"
}
It gives me an error No such property: mongo for class: cmsprofiler.ResourceController
My domain class is as follows:
class Website{
String website
User user
Boolean crawled
static belongsTo = [user: User]
static constraints = {
website( url:true, unique: ['user'])
}
static hasMany = [resource: Resource]
static mapping = {resource cascade:"all-delete-orphan" }
}
you should be using
Website.mongo.update(...)
or let the framework inject it:
class ResourceController {
def mongo
def list(){
mongo.website.update(...)
}
}
This worked for me. Posting it here in case anyone else has similar requirement.
#Grab(group='com.gmongo', module='gmongo', version='0.9.3')
import com.gmongo.GMongo
#Transactional(readOnly = true)
class ResourceController {
def mongo = new GMongo()
def db = mongo.getDB("resources")
def p = Website.findByWebsite(website)
if(p['crawled']==false){
db.website.update([crawled:false],[$set:[crawled:true]])
}