Delete object from array in MongoDB in Java - java

[{
"_id": {
"$oid": "5ee227d69dba6729ca8938fc"
},
"uuid": "4e9be217-a2c7-490f-86b7-2d46a69980a3",
"locks": {
"furnace_1591879638": {
"type": "FURNACE",
"location": {
"world": "world",
"x": -33,
"y": 73,
"z": -227
},
"created": "Thu Jun 11 14:47:18 CEST 2020",
"peopleWithAccess": []
},
"chest_1591903237541": {
"type": "CHEST",
"location": {
"world": "world",
"x": -36,
"y": 73,
"z": -224
},
"created": "Thu Jun 11 21:20:37 CEST 2020",
"peopleWithAccess": []
}
}
},{
"_id": {
"$oid": "5ee2864622c67536a249fb0a"
},
"uuid": "6fc93f76-b03b-4af3-a679-ac53cafdb288",
"locks": {}
}]
Hi,
I just stared with MongoDB and I was used to working with MySQL so this is really confusing for me. I've been trying to delete a object from an array but unsuccessfully. I tried this:
getMongoManager().getDatabase().getCollection("players").updateOne(new Document("uuid", player.getUniqueId().toString()),
new Document("$unset", "locks." + id))
That gave me an error Modifiers operate on fields but we found type string instead.
How would I delete for exmaple object furnace_1591879638 from player with uuid 4e9be217-a2c7-490f-86b7-2d46a69980a3 in Java?

Unfortunately, we cannot use the $unset operator to remove objects from an array, since the operator can only remove whole fields. For removing and inserting in an array, we are using $pull and $push.
I would recommend you to look up, both Bson Updates and Filters class because they are making it way easier, instead of using the operators (At least for the mongodb driver version 3.8 or higher; I do not know if older versions support Bson).
With the help of these classes, you could extend your
MongoManager
class and try something like this:
public void pullByFilter(String queryField, Object queryValue, String arrayName, Object value) {
MongoCollection<Document> collection = getCollection("players");
Bson update = Updates.pullByFilter(Filters.eq(arrayName, value));
collection.updateOne(Filters.eq(queryField, queryValue), update);
}
This method should remove the specified value from the array.
Just for clearance: the queryField and queryValue parameters are used to identify the document (for you, the queryField should be "uuid" and the queryValue should be the players UUID as string).
Lastly, I think the method you tried with the $unset operator is giving you an error because you need to specify a new Document after the operator.
This:
getMongoManager().getDatabase().getCollection("players").updateOne(new Document("uuid", player.getUniqueId().toString()),
new Document("$unset", "locks." + id))
should rather be:
getMongoManager().getDatabase().getCollection("players").updateOne(new Document("uuid", player.getUniqueId().toString()),
new Document("$unset", new Document("locks", id)))
Also, a good tutorial for updating documents can be found here.

Related

How to efficiently merge two JSON Strings based on a common key

I have two JSON strings which are essentially arrays of JSONObject. The two JSON strings have below structure and keys:
JSON-1:
[
{
"title": "ABC",
"edition": 7,
"year": 2011
},
{
"title": "DEF",
"edition": 2,
"year": 2012
},
{
"title": "XYZ",
"edition": 3,
"year": 2013
}
]
And, JSON-2:
[
{
"title": "ABC",
"price": "20"
},
{
"title": "DEF",
"price": "20"
},
{
"title": "XYZ",
"price": "20"
}
]
Both these JSONs have a common key "title" based on which I want to merge these two JSONs, either merging JSON-2 values into JSON-1 or creating a JSON object with the merged result.
The merged result should look like below:
[
{
"title": "ABC",
"edition": 7,
"year": 2011,
"price": "20"
},
{
"title": "DEF",
"edition": 2,
"year": 2012
"price": "20"
},
{
"title": "XYZ",
"edition": 3,
"year": 2013
"price": "20"
}
]
How can I achieve this by minimum looping and minimum object creation? I also can not use entity/model classes. The idea is to do it without creating any model classes.
Note: I cannot use Gson because I don't have the approval to use the same.
I tried to use List<JSONObject> listObj = objectMapper.readValue(jsonOneString, new TypeReference<List<JSONObject>>(){});,
but I am getting an unknown property exception.
I tried JsonNode node = objectMapper.readTree(jsonOneString);, but I cannot proceed much further with this approach.
I know what I am doing here is highly inefficient, so looking for ways which will use no entity class, minimum new object creation and minimum loops. Kindly advise.
UPDATE: I updated the below code with a slight modification:
if (json1elem.get("title")!=null
&& json2elem.get("title")!=null
&& json1elem.get("title").equals(json2elem.get("title"))) {
//
}
JsonNode json1 = objectMapper.readTree(jsonOneString);
JsonNode json2 = objectMapper.readTree(jsonTwoString);
for (JsonNode json1elem : json1) {
for (JsonNode json2elem : json2) {
if (json1elem.get("title").equals(json2elem.get("title"))) {
((ObjectNode) json1elem).setAll((ObjectNode) json2elem);
break;
}
}
}
System.out.println(json1.toPrettyString());

Spring Boot how to update a field within an array in MongoDB

I am quite new to Spring Boot and MongoDB. I am trying to update the availability for a specific user within the user array. The issue is that I am trying to find a specific username for example: "Mark" and update that entry only. However, it could be under any index of the array, and I'm not quite sure how write that in the query statement.
The structure of my data in mongoDB:
{
"name": "test meeting",
"url": "temporary_url",
"timezone": "pacific",
"startTime": 8,
"endTime": 21,
"users": [
{
"username": "Mark",
"password": "Caddy",
"availability": { << TRYING TO UPDATE THIS
//array of objects
}
},
{
"username": "Bill",
"password": "Bobby",
"availability": {
//array of objects
}
}
],
"_class": "com.dcproduction.meetapp.classes.Meeting"
}
Below is my attempt to make it work. It works if I substitute an index for [WHAT GOES HERE] such as '0', but the point of this query is that I wouldn't normally know which index the name would fall under:
Query query = new Query();
query.addCriteria(
new Criteria().andOperator(
Criteria.where("name").is("test meeting"),
Criteria.where("users.[WHAT GOES HERE?]username").is("Mark")));
Update testUpdate = new Update();
testUpdate.set("users[WHAT GOES HERE].availability", some_data);
UpdateResult updateResult = mongoTemplate.updateFirst(query, testUpdate, Meeting.class);
Any help would be appreciated, thanks!
You could use identifiers as mentioned here: https://www.mongodb.com/docs/manual/reference/operator/update/positional-filtered/
which would be of the form:
query.addCriteria(
Criteria.where("users._username").is("Mark")
);
update.set("users.$[selector].availability", some_data)
.filterArray(Criteria.where("selector._username").is("Mark"));

How can I store and update the nested json object into couchbase using java sdk

I am using couchbase Community Edition 5.0.1 and java-client 2.7.4. I want to store the following nested json object into couchbase. If I want to update the same object without affecting the other fields.
Eg:
If I want to add one more player object under players object
array
If I want to add One more group say 'Z Group' under group object array
How can I Achieve this without affecting other fields.
{
"doctype": "config:sample",
"group": [{
"name": "X Group",
"id": 1,
"players": [{
"name": "Roger Federer",
"number": 3286,
"keyword": "tennies"
},
{
"name": "P. V. Sindhu",
"number": 4723,
"keyword": "badminton"
}
]
},
{
"name": "Y Group",
"id": "2",
"players": [{
"name": "Jimmy Connors",
"number": 5623,
"keyword": "tennies"
},
{
"name": "Sachin",
"number": 8756,
"keyword": "Cricket"
}
]
}
]
}
N1QL has a huge variety of functions to operate on arrays:
https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/arrayfun.html
In your case, you could simply use ARRAY_INSERT or ARRAY_PREPEND
Check out update/update-for syntax (last example) https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/update.html
UPDATE default AS d
SET d.group = ARRAY_APPEND(d.group, {......})
WHERE .....;
UPDATE default AS d
SET g.players = ARRAY_APPEND(g.players, {......}) FOR g IN d.group WHEN g.id = 2 END
WHERE .....;
If you know which document IDs you want to update you can use the key-value subdocument API, which will generally be faster than going via N1QL for a single document update.
This will add a new player to the end of X Group's "players" array:
bucket.mutateIn(docId)
.arrayAppend("group[0].players",
JsonObject.create()
.put("name", "John Smith"))
// ... other player JSON
.execute();
And this will add a new Group Z to the "group" array:
bucket.mutateIn(docId)
.arrayAppend("group",
JsonObject.create()
.put("name", "Z Group"))
// ... other group JSON
.execute();

Move document from one collection to another is overwriting the document

With the first operation by matching with id[1602271], its creating new collection and saving one doc(below-mentioned doc).
{
"_id": "1602271",
"date": "2019-02-11T06:25:13.425Z",
"currentStatus": "scheduled",
"statusHistory": [
{
"status": "onboarded",
"date": "2018-11-02T10:07:11.167Z"
},
{
"status": "preference_ready",
"date": "2018-11-02T10:08:56.359Z"
},
{
"status": "scheduled",
"date": "2018-11-02T10:26:38.721Z"
}
]
}
With the second operation id[1602131], it's not creating a new doc instead it's overwriting with the older one (above JSON).
{
"_id": "1602131",
"date": "2019-01-22T07:08:58.253Z",
"currentStatus": "scheduled",
"statusHistory": [
{
"status": "onboarded",
"date": "2018-11-02T06:07:28.765Z"
},
{
"status": "preference_ready",
"date": "2018-11-02T06:11:30.777Z"
},
{
"status": "scheduled",
"date": "2018-11-29T05:48:57.871Z"
}
]
}
Please refer below-mentioned code:
public static final String STATUS_COLLECTION_NAME = "TeacherStatus";
public static final String ARCHIVE_STATUS_COLLECTION_NAME =
"ArchiveTeacherStatus";
Aggregation aggregation = Aggregation.newAggregation(match(where("_id").is(teacherId)),
out(ARCHIVE_STATUS_COLLECTION_NAME));
mongoOperations.aggregate(aggregation, STATUS_COLLECTION_NAME, TeacherStatus.class);
Works as intended. https://docs.mongodb.com/manual/reference/operator/aggregation/out/
If the collection specified by the $out operation already exists, then upon completion of the aggregation, the $out stage atomically replaces the existing collection with the new results collection.
It will be possible in mongodb 4.2 where $out stage will accept an additional parameter mode, which can take values "replaceCollection" (what happens now), "replaceDocuments", "insertDocuments" (what you want).
Having re-read your code, why are you using aggregation pipeline with $out to copy one document? That's hunting sparrows with a cannon.
You can do it more reliably through the app. Read the document, then save it into the other collection.

Custom formatting for pretty-printing JSON data Java

I'm looking for a way I can create a custom formatting "rule/s" of some sort for pretty-printing JSON data. Currently, I'm using GSON to prettyprint, however, I'd like to output in a different format. To be more specific, I am trying to match the formatting of Minecraft JSON files.
Here's an example of GSON pretty-print:
[
{
"when": {
"OR": [
{
"conditional": false,
"facing": "north"
},
{
"conditional": false,
"facing": "north"
}
]
},
"apply": [
{
"model": "chain_command_block",
"weight": 1,
"uvlock": false,
"x": 0,
"y": 0
}
]
}
]
And here's an example of what I am trying to achieve:
[
{ "when": { "OR": [
{"conditional": false, "facing": "north"},
{"conditional": false, "facing": "north"}
]},
"apply": [
{ "model": "chain_command_block", "weight": 1, "uvlock": false, "x": 0, "y": 0 }
]
}
]
I think I'm going to have to manually format and output the data myself using a StringBuilder or a BufferedWriter but if anyone else has any other ideas, please let me know.
Any help is appreciated, thanks.
With GSON, you can register a typeAdapter and customise how a class should be serialised and deserialised.
https://futurestud.io/tutorials/gson-advanced-custom-serialization-part-1
EDIT: With this method, although you can define what data is used and how it's presented (in an array or a csv string etc...), I don't think you can actually change the structure of the pretty-printing.
For example, if I wanted to pretty-print an object, I also want to be able to define when to indent and when to move down to the next line for a certain class type. Still testing though so maybe I'm wrong,,,

Categories

Resources