I am writing a CRUD app using Quarkus and Mongo, and thus am using a MongoCollection to implement this.
I am utilizing Hibernate Validators for validation to ensure my data is as it should be.
The issue I am running into is that the MongoCollection only provides updates using Bson (collection.updateOne(Bson search, Bson update)), and not for the entire object. This would be fine but keeps me from being able to properly use validators to ensure proper data integrity.
Until I hit this block, my idea for updating was to:
ingest generic json, in the form of ObjectNode and the object's id
get the object to update
Use Jackson's built-in updating features to apply the updates to the object from the given ObjectNode
Validate the resulting state
save the object to Mongo
However, this doesn't work when I can't update the whole object at once. Am I attacking this from the right angle? I've found a lot on how to do updates, but not a lot related to validation. I also see that I can specify on the Mongo side validation rules, but as I am fairly 'hands off' when using Mongo in this way, so needing to apply special Bson validation isn't ideal.
Is it possible for me to just re-insert the updated object to Mongo using `collection.insertOne(object)`? this assumes that the object would have the same `_id` as the original. Would this update the object as intended, or are there side effects?
Edit:: no, it is not. Mongo throws an error for duplicate keys.
Found it, what I wanted was collection.findOneAndReplace()
Related
I would like to hook an event after an object is retrieved from the database. This event should be fired regardless if the object is retrieved from .find() or via a .populate() call. I would think it should be similar to the other lifecycle callbacks like afterCreate or afterUpdate, etc.
Is this possible to do with Waterline and if so, how can it be accomplished?
To give an idea of what I'm trying to accomplish: I'm using Mongo to
store my data. There is the potential that the model schema has
changed since the record was last saved. I'd like to "upgrade" the
record retrieved from the database to the latest version using a
function defined on the model itself. I would like this process to
happen as transparently as possible after a query returns (ie. Not
have to explicitly call the function in each query callback function).
I would like to be able to track the mutated (modified) attributes of an object in sails during afterUpdate lifecycle callback.
Assuming an object is updated I would like to know which attribute has been modified during the update operation, I've been using sails-mongo and I believe I could write a proxy adapter that keep a local instance and attach it to the one thats going to be modified and do a diff on save but there might be an already existing way of doing so :)
Thanks !
Waterline doesn't currently have a built in diff mechanism. To accomplish this you can explore the use of native queries where some databases will allow you to return the values being updated or store the previous records in a diff on the record in the database.
afterUpdate won't be able to handle this because by then the results have already been updated in the database. You could write a controller method that uses the same criteria to capture all the records before you issue the update criteria.
I have been trying to get my head wrapped around MongoDB, as it's used by Spring, so I decided to start a little project in Spring Roo.
In my project, I am storing my User Login data to MongoDB. The trouble is that the registration process, which creates a new User object and stores it in the MongoDB, has a tendency to create duplicates despite the fact I have #Unique on the loginId field.
Now, I know part of the problem is that I am thinking about things from a JPA/RDBMS perspective, and MongoDB is not a relational DB and thus has a different set of parameters in which to operate with, but I having trouble finding guidance in anything more than a VERY simple sample code.
First, what Spring/Other annotations are available, and more importantly, commonly used when dealing with MongoDB from a Spring-world? Second, when dealing with documents that need to be "uniqued", how does one typically do this? Do you first search on the unique field to ensure it's not already there first, then do the insert? Third, in JPA-land, I could use the annotations #PrePersist and #PreUpdate to do last-minute data manipulation, like MD5-hashing passwords that have been updated or adding/updating a "Last Modified" date just prior to storing. I know this are JPA-isms, but can I still use those, and if not, is there an alternative for use with Spring Data/MongoDB?
I ended up using the #Id annotation on my Entities, which indicates which field is used as the id field. As long as the field is unique, writting subsequent updates will properly replace the existing entity instead of adding a new one.
I ended up creating additional method to check if there exists a data which have a duplicate value to the one we are entering.
If it exists, i return failure mentioning that there exist duplicate value. Otherwise it saves the newly entered value
I'm working on a project with Scala, Salat, Casbah, Mongo, Play2, BackboneJS... But it's quite a lot of new things to learn in the same time... I'm ok with Scala but I find my code crappy and I don't really know what's the solution to improve it.
Basically my usecase is:
A MongoDB object is sent to the browser's JS code by Play2
The JS code update the object data (through a Backbone model)
The JS send back the the updated JSON to the server (sent by Backbone save method, and received by Play with a json bodyparser)
The JSON received by Play should update the object in MongoDB
Some fields should not be updatable for security reasons (object id, creationDate...)
My problem is the last part.
I'm using case classes with Salat as a representation of the objects stored in MongoDB.
I don't really know how to handle the JSON i receive from the JS code.
Should I bind the JSON into the Salat case class and then ask Mongo to override the previous object data by the full new case class object?
If so is there a way with Play2 or Salat to automatically create back the case class from the received JSON?
Should I handle my JSON fields individually with $set for the fields I want to update?
Should i make the elements of my case class mutable? It's what we actually do in Java with Hibernate for exemple: get the object from DB, change its state, and save it. But it doesn't seem to be the appropriate way to do with Scala...
If someone can give me some advices for my usecase it would be nice because I really don't know what to do :(
Edit: I asked a related question here: Should I represent database data with immutable or mutable data structures?
Salat handles JSON using lift-json - see https://github.com/novus/salat/wiki/SalatWithPlay2.
Play itself uses Jerkson, which is another way to decode your model objects - see http://blog.xebia.com/2012/07/22/play-body-parsing-with-jerkson/ for an example.
Feel free to make a small sample Github project that demonstrates your issue and post to the Salat mailing list at https://groups.google.com/group/scala-salat for help.
There are really two problems in your question:
How do I use Play Salat.
How do I prevent updates to certain fields.
The answer to your first question lies in the Play Salat documentation. Your second question could be answered a few ways.
a. When the update is pushed to the server from Backbone, you could grab the object id and find it in the database. At that point you have both copies of the object. At that point, you can fire a business rule to make sure the sender didn't attempt to change those fields.
or
b. You could put some of your fields in another document of an embedded document. The client would have access to them for rendering purposes but your API wouldn't allow them to be pushed back to Mongo.
or
c. You could write a custom update query that ignores the fields you don't want changed.
Actually the answer is pretty simple: I didn't know there was a built-in copy method on case classes that allows to copy an immutable case class while changing some data.
I don't have nested case class structures but the Tony Morris suggestion of using Lenses seems nice too.
We are using mongodb with c#. We are trying to figure out a way to keep our collection consistent seamlessly. Right now, if a developer make any changes to the class structure(add a field or change data type or changing the property within a nested class) he/she has to change the mongo collection manually.
Its a pain as our project is growing and the developers working on the project keeps increasing. Was wondering whether someone already have figured out a way to manage this issue.
Research
I found a similar question. however, couldn't find the solution.
Found a way to find all properties Finding the properties; however, datatype and nested documents becomes an issue.
If you want to migrate gradually as records are accessed you need to follow a few simple rules:
1) If you add a field it had better be nullable or have a default value specified.
2) Never rename fields, never change field types
- Instead always add new fields, add migration code, remove the old fields only when all documents have been migrated over.
For prototyping with MongoDB and C# I build a dynamic wrapper ... that lets you specify your objects using only interfaces (no classes needed), and it lets you dynamically add new interfaces to an existing object. Not ready for production use but for prototyping it saves a lot of effort and makes migration really easy.