MongoDB upsert array document with golang - mongodb

I have a document like below:
{
"_id": "1.0",
files: [
{"name": "file_1", "size": 1024, "create_ts": 1570862776426},
{"name": "file_2", "size": 2048, "create_ts": 1570862778426}
]
}
And I want to upsert “files” with "file_x":
1 if "file_x" already in "files", then update, for example "file_x" is:
{"name": "file_2", "size": 4096, "create_ts": 1570862779426}
after upsert document is:
{
"_id": "1.0",
files: [
{"name": "file_1", "size": 1024, "create_ts": 1570862776426},
{"name": "file_2", "size": 4096, "create_ts": 1570862779426}}
]
}
2 if "file_x" not in "files", insert it, for example "file_x" is:
{"name": "file_3", "size": 4096, "create_ts": 1570862779426}
after upsert document is :
{
"_id": "1.0",
files: [
{"name": "file_1", "size": 1024, "create_ts": 1570862776426},
{"name": "file_2", "size": 2048, "create_ts": 1570862778426},
{"name": "file_3", "size": 4096, "create_ts": 1570862779426}
]
}
So can I use one function to archive it ?

You will need to do this manually. There's no upsert mechanism for embedded structures inside a document.
First fetch the document, check if file_x is in the files list, if not, insert it. Then save the document back.
You should make sure that at any given time, only one program / goroutine is trying to do this, otherwise you will run into race conditions and file_x might get inserted multiple times.

There is not a single update operation in mongodb update language that will do what you want to do. You can get close by using $addToSet, which adds to a set of items if the item is not already there, but it will not update the item based on the match of a subset of fields. Your best option is to perform a read-update in memory-write.

Related

Data Modeling for table in MongoDB

I have a hypothetical table with the following information about cost of vehicles, and I am trying to model the data for storing into a Expenses collection in MongoDB:
Category
Item
Cost
Land
Car
1000
Land
Motorbike
500
Air
Plane
2000
Air
Others: Rocket
5000
One assumption for this use case is that the Categorys and Items are fixed fields in the table, while users will fill in the Cost for each specific Item in the table. Should there be other vehicles in the category, users will fill them under "Others".
Currently, of 2 options to store the document:
Option 1 - as a nested object:
[
{
"category": "land",
"items": [
{"name": "Car", "cost": 1000},
{"name": "Motorbike", "cost": 500},
]
}
{
"category": "air",
"items": [
{"name": "Plane", "cost": 2000},
{"name": "Others", remarks: "Rocket", "cost": 5000},
]
}
]
Option 2 - as a flattened array, where the React application will map the array to render the data in the table:
[
{"category": "land", "item": "car", "cost": 1000},
{"category": "land", "item": "motorbike", "cost": 500},
{"category": "air", "item": "plane", "cost": 2000},
{"category": "air", "item": "others", "remarks": "rocket", "cost": 5000},
]
Was hoping to get any suggestions on which is a better approach, or if there is a better approach that you have in mind.
Thanks in advance! :)

How to update a property of a sub-document in an embedded array?

Given the following document in the database, I want to update pincode of address array.
I'm using the $ positional locator in Mongodb. But this does not find the document embedded multiple levels.
"_id": ObjectId("58b91ccf3dc9021191b256ff"),
"phone": 9899565656,
"Email": "sumit#mail.com",
"Organization": "xyz",
"Name": "sumit",
"address": [{
"city": "chennai",
"pincode": 91,
"_id": ObjectId("58b91db48682ab11ede79b28"),
"choice": [{
"_id": ObjectId("58b91fa6901a74124fd70d89")
}]
}]
Using this query to update.
db.presenters.update({"Email":"sumit#mail.com","address.city":"chennai"},{$set:{"address.$.pincode.": 95 }})
You seem to have incorrect field name while updating, an extra dot at the end. Try following
db.presenters.update({"Email":"sumit#mail.com","address.city":"chennai"},
{$set:{"address.$.pincode": 95 }})

MongoDB, remove nested doc in an array

I have the following structure in MongoDB and I try to remove the documents that contains specific tags. I can't seem to be able to get the $pull work.
In this example, I would like to pull the nested doc that has has tags :["BB"]
Any help will be appreciated !
{
"_id": 123,
"socialItems": {
"facebook": [{
"name": "firstFacebook",
"id": 2
}, {
"name": "secondFB",
"id": 43
}],
"instagram": [{
"name": "firstNstagram",
"id": 4
}],
"pc": [{
"name": "firstPC",
"id": 55,
"tags": [
"ab"
]
}, {
"name": "secondPC",
"id": 66,
"tags": [
"BB"
]
}]
}
}
I assume you are trying to drop the nested 'pc' doc, from the array? You also don't mention if you're using a specific driver for this, so I've assumed you're running this in the Mongo shell.
The following will remove documents from the 'pc' property, when containing the 'BB' tag.
db.collectionName.update({'socialItems.pc.tags': 'BB'}, {$pull: {'socialItems.pc': {tags: 'BB'}}})

Getting search result from elastic4s in scala

I have the following code and I am trying to get all the hits from the elasticsearch. If I try to write without the query part it only gives me 10 results when I call .getHits.
val resultFuture = client.execute {
search in "reports/reportOutput" query{ termQuery("mainReportID", reportId.toString)}
}.await
Another issue is that the query part does not actually work and I get nothing. Here is a structure from my elasticsearch.
"hits": {
"total": 266,
"max_score": 1,
"hits":[
{
"_index": "reports",
"_type": "reportOutput",
"_id": "AUwjbAuKTetnUx12_a97",
"_score": 1,
"_source":
{
"displayName": "Classic BMW / MINI",
"model": "Cooper Clubman",
"dayInStock": "10",
"stockNumber": "Q323A",
"miles": "81093",
"interiorColorGeneric": "Black",
"year": "2009",
"trimLevel": "",
"mainReportID": "4d9e4fd3-7fdf-41c8-8c29-45c5acaf78b1",
"modelNumber": "",
"exteriorColorGeneric": "White",
"exteriorColor": "Pepper White",
"vin": "WMWML33509TX35944",
"make": "MINI",
"transmission": "A",
"exteriorColorCode": "850",
"interiorColor": "Gray/Carbon Black",
"interiorColorCode": "K8E1"
}
},
You can increase how many results are returned by setting a limit on the request, for example:
search in "index" limit 100
But the default limit of 10 is not set by elastic4s but by elasticsearch itself and you cannot change it to return all results by default.

How to create a (double) linked list structure in MongoDB?

I'm trying to store a multitude of documents which are double linked i.e. they can have a predecessor and a successor. Since the collection exists of different documents I'm not sure if I can create a feasible index on it:
{"_id": "1234", "title": "Document1", "content":"...", "next": "1236"}
{"_id": "1235", "title": "Document2", "content":"...", "next": "1238"}
{"_id": "1236", "title": "Document1a", "content":"...", "prev": "1234"}
{"_id": "1237", "title": "Document2a", "content":"...", "prev": "1235", "next": "1238"}
{"_id": "1238", "title": "Document2b", "content":"...", "prev": "1237", "next": "1239"}
...
Since I'll need the whole 'history' of a document including prev and next documents I guess I'll have to perform a multitude of querys depending on the size of the list?
Any suggestions on how to create a performant index? A different structure for storing double linked lists would also be interesting.
If you want to optimize reading you can use arrays to store previous and next documents.
{
"_id": "1237",
"title": "Document1",
"content":"...",
"next": "1238",
"prev": "1235",
"parents" : [1000, 1235]
"children" : [1238, 1239]
}
You can then get all the documents where your _id is either in child or parents array. This solution is good if you only need parents or children of the document. To get a whole list you can't efficiently use indexes with $or and two $in operators.
Alternative and probably a better solution is to store the entire list for each document i.e. child and parents in one array:
{
"_id": "1237",
"title": "Document1",
"content":"...",
"next": "1238",
"prev": "1235",
"list_ids" : [1000, 1235, 1238, 1239, 1237]
}
That way you can have an index on list_ids and get all the documents with a simple $in query that will be fast.
The problem with both of the solutions is that you will need to update all related documents when you add a new document. So this is probably not a good solution if you're
going to have a write heavy app.