retrieving vavr collection via spring data rest from mongo db doesn't work - mongodb

I created a small spring boot project to retrieve a sample object from mongoDb via spring data rest which contains a Seq (vavr collection). Immediately after booting the app it doesn't work. At first I have to do an insertion and afterwards it works to call teh repo's rest endpoint.
Error msg from log
Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Couldn't find PersistentEntity for type class io.vavr.collection.List$Cons!; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Couldn't find PersistentEntity for type class io.vavr.collection.List$Cons! (through reference chain: org.springframework.hateoas.PagedResources["_embedded"]->java.util.Collections$UnmodifiableMap["myEntities"]->java.util.ArrayList[0]->org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer$1["content"]->de.spring.demo.entity.MyEntity["myList"])
It sounds like some mappers have to be injected which are automatically injected after inserting a new entry (or some lazy loading maybe...)
A sample can be found here: https://github.com/renne-b/spring-rest-demo
It would be great to get a hint what's missing.
some details:
latest spring boot milestone: 2.0.0.M3
I registered VavrModule at ObjectMapper
#EnableMongoRepositories(basePackages = "for my path to classes")

I update your project with
Spring boot 2.0.0.RELEASE
EmbeddedMongo de.flapdoodle.embed:de.flapdoodle.embed.mongo:2.0.3 / 3.2.2:Windows:B64
Fix JSON mapping
And after that request curl http://localhost:8080/myEntities executed without problems:
{
"_embedded" : {
"myEntities" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/myEntities{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:8080/profile/myEntities"
}
},
"page" : {
"size" : 20,
"totalElements" : 0,
"totalPages" : 0,
"number" : 0
}
}
After add 2 entities:
{
"_embedded" : {
"myEntities" : [ {
"foo" : "bar1521033137701",
"myList" : {
"content" : [ "bla" ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/myEntities/5aa91fb1bec7c7169c9b5943"
},
"myEntity" : {
"href" : "http://localhost:8080/myEntities/5aa91fb1bec7c7169c9b5943"
}
}
}, {
"foo" : "bar1521033145175",
"myList" : {
"content" : [ "bla" ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/myEntities/5aa91fb9bec7c7169c9b5944"
},
"myEntity" : {
"href" : "http://localhost:8080/myEntities/5aa91fb9bec7c7169c9b5944"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/myEntities{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:8080/profile/myEntities"
}
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}

Related

Mongo DB update query [duplicate]

This question already has answers here:
Can you specify a key for $addToSet in Mongo?
(2 answers)
Closed 4 years ago.
I have the below document stored in mongo DB collection,I will need to add new subscribers For eg.,I need to add the subscriber with "protocol" : "SOAP" and url http://localhost.8080/FNOL/subscriber3 for the name "name" : "FNOL","country" : "US","lob" : "property" from the document.
If the url we are adding already exist we shouldn't add to the document,in case if the document does not exist with matching criteria name "name" : "FNOL","country" : "US","lob" : "property" i would need to insert a new document.
is it possible to do all the above in a single command in mongo db?
Thanks in advance.
{
"_id" : ObjectId("5b07fbbc0d7a677d2f8b2d87"),
"name" : "FNOL",
"country" : "US",
"lob" : "property",
"subscribers" : [
{
"protocol" : "REST",
"url" : "http://localhost.8080/FNOL/subscriber1"
},
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber2"
},
{
"protocol" : "JMS",
"url" : "NOTIFICATION.TOPIC.FNOL"
}
]
}
After updation:
{
"_id" : ObjectId("5b07fbbc0d7a677d2f8b2d87"),
"name" : "FNOL",
"country" : "US",
"lob" : "property",
"subscribers" : [
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber2"
},
{
"protocol" : "JMS",
"url" : "NOTIFICATION.TOPIC.FNOL"
},
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber2"
}
,
{
"protocol" : "SOAP",
"url" : "http://localhost.8080/FNOL/subscriber3"
}
]
}
You need to use $addToSet... It will not push the data if it already exist in the array
db.collection.update(
{ name: 'FNOL', country: 'US', lob: 'property' },
{ $addToSet: { subscribers: { "protocol" : "SOAP", url: 'http://localhost.8080/FNOL/subscriber3' } } },
{ upsert: true }
)
Try this.
db.collection.update( { "_id": (id of the object) }, { "$push": {"subscribers": { "url": "(input url )", "protocol": "(input protocol)" } } } )

How to get multiple fields at once?

I have been typing this query
db.sInsert.find(
{post_id:"28011986676_10155780942281677"},
{comments_data: 1, _id:0}
)
And I got this result from MongoDB.
{
"comments_data": {
"id": "28011986676677",
"comments": {
"paging": {
"cursors": {
"after": "WTI5dGJXVnVkRjlqZAFhKePQT09",
"before": "WTI5dGJXVnVkRjlqZAFhKEWXlPQT09"
}
},
"data": [
{
"created_time": "2018-01-03T21:23:47+0000",
"message": "Poor customer care service after became the customer.I did my re contract they send acknowledgement email confirmation after no followup.I called again and remains no proper response and action extremely worst customer care service.",
"from": {
"name": "Sun",
"id": "102023391"
},
"id": "10155784116677"
}
]
}
}
}
How do I get the post_id and message only from comments_data?
And i want to group by the post_id
Below is a sample of how my documents looks like in my mongoDB
{
"_id" : ObjectId("5a43aa19d4b45e362428e2da"),
"comments_data" : {
"id" : "28011986676_10155780942281677",
"comments" : {
"paging" : {
"cursors" : {
"after" : "WTI5dGJXVnVkRjlqZAFhKemIzSTZAN4TlRBeE5EWXlPQT09",
"before" : "WTI5dGJXVnVk4TVRZAMk56YzZANVFV4TlRBeE5EWXlPQT09"
}
},
"data" : [
{
"created_time" : "2018-01-03T21:23:47+0000",
"message" : "Poor customer care service after became the Singtel customer.I did my re contract they send acknowledgement email confirmation after no followup.I called again and remains no proper response and action extremely worst customer care service.",
"from" : {
"name" : "Sundararaju G",
"id" : "1020391"
},
"id" : "10155780942281677_10155811924116677"
}
]
}
},
"post_id" : "28011986676_10155780942281677",
"post_message" : "\"Singtel TV celebrated our 10th birthday with 10 awesome experiences for our customers! Each of our winners won a trip of a lifetime - from attending the Emmy Awards, getting a magical princess treatment at Disneyland, to catching a Premier League game live in London! We thank all our customers for your support and we look forward to more great years to come!\"",
"reactions_data" : {
"reactions" : {
"paging" : {
"cursors" : {
"after" : "TVRBd01EQXpNVEF5T1Rje4TXc9PQZDZD",
"before" : "TVRjNE56TTBBek56a3hNek14TWc9PQZDZD"
},
"next" : "https://graph.facebook.com/v2.7/280119866761677/reactions?access_token=EAA"
},
"data" : [
{
"type" : "ANGRY",
"id" : "1020573391",
"name" : "Sundararaju Gh"
},
{
"type" : "LIKE",
"id" : "64721496",
"name" : "Zhiang Xian"
}
]
},
"id" : "28011986676_102281677"
}
}
Another sample
{ "_id" : ObjectId("5a43aa19d4b45e362428e2ee"), "comments_data" : { "id" : "28011986676_10155778255601677",
"comments" : { "paging" : { "cursors" : { "after" : "WTI5dGJXV5zZANVFV4TXpjM09UTTVNUT09" } },
"data" : [ { "created_time" : "2017-12-20T14:16:31+0000", "message" : "Putri Thang Michael Herman hahaha maret jg", "from" : { "name" : "Caterine Liang", "id" : "10153088743299160" }, "id" : "10155778255601677_101171677" }, { "created_time" : "2017-12-20T16:38:12+0000", "message" : "Pauline Chan", "from" : { "name" : "Nitin Aggarwal", "id" : "10153185412203152" }, "id" : "10155778255601677_10155779456916677" } ] } },
"post_id" : "28011986676_10155778255601677",
"post_message" : "\"Peppa Pig and friends return to Singapore in a new musical LIVE show that\\u2019s bigger than ever with life-sized mascots. Singtel mobile subscribers enjoy exclusive priority sale and 15% off tickets to PEPPA & FRIENDS LIVE on Stage from 20 Dec \\u201817. Get your tickets at now. T&Cs apply.\"",
"reactions_data" : { "reactions" : { "paging" : { "cursors" : { "after" : "TVRBd01EQXpNREkwTVRc9PQZDZD", "before" : "TVRBd0c9PQZDZD" }, "next" : "https://graph.facebook.com/v2.7/28011986676_1601677/reactions?access_token=EAA" }, "data" : [ { "type" : "LIKE", "id" : "1263712690368750", "name" : "Alice Lo" }, { "type" : "LIKE", "id" : "130228537768890", "name" : "Gina Sangoy" }, { "type" : "LIKE", "id" : "478172222283410", "name" : "Jiamin Feng" }, { "type" : "LIKE", "id" : "10152186445293439", "name" : "Ann Wong" }, { "type" : "LIKE", "id" : "164905927597888", "name" : "ស្រីនាថ ពោធិ៍សាត់" }, { "type" : "LIKE", "id" : "694456787260426", "name" : "Lim Kian Heng" }, { "type" : "LIKE", "id" : "135201790538289", "name" : "Anasta Clara" }, { "type" : "LIKE", "id" : "10154040401150853", "name" : "Jacqueline Salim JingYuan" }, { "type" : "LIKE", "id" : "1428497527466013", "name" : "Izhan Sawalha" }, { "type" : "LIKE", "id" : "10152590923001843", "name" : "Ellena Liu" }, { "type" : "LIKE", "id" : "28011986676_1077" } }
This command ...
db.sInsert.find(
{post_id:"28011986676_10155780942281677"},
{'comments_data.comments.data.message': 1, _id:0}
)
... will return:
{
"comments_data" : {
"comments" : {
"data" : [
{
"message" : "Poor customer care service after became the customer.I did my re contract they send acknowledgement email confirmation after no followup.I called again and remains no proper response and action extremely worst customer care service."
}
]
}
}
}
In the document you supplied, the path to message is: comments_data.comments.data.message so that's the correct path to use in the projeciton argument to the find() method.
If the desired output is only message, in the sense of flattening the response to remove the intermediate levels, then this command ...
db.sInsert.aggregate([
{ $match: {post_id: {"$eq": "28011986676_10155780942281677" } } },
{ $project: {'message': '$comments_data.comments.data.message', _id:0} },
])
... will read the same data but will reshape the output into this:
{
"message" : [
"Poor customer care service after became the customer.I did my re contract they send acknowledgement email confirmation after no followup.I called again and remains no proper response and action extremely worst customer care service."
]
}

cloudformation Template format error: Every Resources object must contain a Type member

Hi I hope someone can help tell me what I am doing wrong. I am writing a CF template that just adds a VPN Gateway to a VPC. No need to update routing tables etc.
I am using the below template but I get an error that I can't quite see the problem, I thought an extra pair of eyes might help!
:
Template validation error: Template format error: Every Resources object must contain a Type member.
Template:
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "CF Just add a VPN Gateway to a VPC ",
"Parameters" : {
"targetVPCtoAttachGatewayTo" : {
"Description" : "VPC ID to attach VPN Gateway",
"Default" : "vpc-xxxxx",
"Type": "AWS::EC2::VPC::Id"
}
},
"Resources" : {
"VPNGateway" : {
"Type" : "AWS::EC2::VPNGateway",
"Properties" : {
"Type" : "ipsec.1",
"Tags" : [
{"Key": "Name", "Value": {"Fn::Join": ["",["Virtual Private Gateway for ", { "Ref": "targetVPCtoAttachGatewayTo"} ] ]}}]
}
},
"AttachVpnGateway" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"DependsOn" : "VPNGateway",
"Properties" : {
"VpcId" : { "Ref" : "targetVPCtoAttachGatewayTo" },
"VpnGatewayId" : { "Ref" : "VPNGateway" }
}
},
"Outputs" : {
}}}
Resolved the issue, curly brackets in the wrong place. Working template below.
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "CF Just add a VPN Gateway to a VPC ",
"Parameters" : {
"targetVPCtoAttachGatewayTo" : {
"Description" : "VPC ID to attach VPN Gateway",
"Default" : "vpc-xxxxx",
"Type": "AWS::EC2::VPC::Id"
}
},
"Resources" : {
"VPNGateway" : {
"Type" : "AWS::EC2::VPNGateway",
"Properties" : {
"Type" : "ipsec.1",
"Tags" : [
{"Key": "Name", "Value": {"Fn::Join": ["",["Virtual Private Gateway for ", { "Ref": "targetVPCtoAttachGatewayTo"} ] ]}}]
}
},
"AttachVpnGateway" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"DependsOn" : "VPNGateway",
"Properties" : {
"VpcId" : { "Ref" : "targetVPCtoAttachGatewayTo" },
"VpnGatewayId" : { "Ref" : "VPNGateway" }
}
}
},
"Outputs" : {
}}

MongoDB aggregation and projection issue

helpful people of StackOverflow!
I'm in the process of learning how to work with MongoDB, and am currently stuck with one particular problem.
I'm building a guitar tabs app, working only with an "artist" base document. All other data are subdocuments. Depending on the accessed functionality (e.g: search, list tabs by artist, view single tab), I aggregate and project my documents accordingly.
However, I can't get one projection to work as I want.
Given the following data:
{
"artist" : "Jeff Buckley",
"songs" : [
{
"name" : "Grace",
"tabs" : [
{
"version" : 1,
"tab" : "...",
"tuning" : "DADGBe"
},
{
"version" : 2,
"tab" : "...",
"tuning" : "DADGBe"
}
]
},
{
"name" : "Last Goodbye",
"tabs" : [
{
"version" : 1,
"tab" : "...",
"tuning" : "DGDGBD"
},
{
"version" : 2,
"tab" : "...",
"tuning" : "EADGBe"
}
]
}
]
}
I want to aggregate it the following way for a list view:
{
"artist" : "Jeff Buckley",
"tabs" : [
{
"song" : "Grace",
"version" : 1
},
{
"song" : "Grace",
"version" : 2
},
{
"song" : "Last Goodbye",
"version" : 1
},
{
"song" : "Last Goodbye",
"version" : 2
},
]
}
I tried it with the following projection:
db.tabs.aggregate(
[
{
$project : {
artist : 1,
tabs.song : "$songs.name",
tabs.version : "$songs.tabs.version"
}
}
]
)
But instead I got:
{
"artist" : "Jeff Buckley",
"tabs" : {
"version" : [[2,1],[2,1]],
"song" : ["Grace","Last Goodbye"]
}
}
Can anyone point me in the right direction?
Thanks!
your aggregation query not correct $project only affect your json document keys
your aggretion query like this
db.tabs.aggregate(
{$unwind : "$songs"},
{$unwind : "$songs.tabs"},
{$group : {
_id:"$artist",
tabs:{$push : {song : "$songs.name",version:"$songs.tabs.version"}}}},
{$project : {
tabs:"$tabs",
artist:"$_id",
_id:0}}
).pretty()

MongoDB ReduceMap An Array Property that Contains Another Array

I'm still new to MongoDB and non-relational databases in general so if the answer to my question is "Dude, you're thinking about your data in the wrong way", please let me know.
That being said, here's what I'm after. I have the following data:
{
"_id" : ObjectId("549b26b370b452eeb6acecd3"),
"user" : "54530e03c575dc86d61d22f8",
"workHistory" : [
{
"description" : "",
"endDate" : null,
"name" : "My Company",
"skills" : [
{
"_id" : ObjectId("549b29c970b452eeb6acecd4")
},
{
"_id" : ObjectId("549b29c970b452eeb6acecd5")
},
{
"_id" : ObjectId("549b29c970b452eeb6acecda")
},
{
"_id" : ObjectId("549b29c970b452eeb6acecdb")
},
{
"_id" : ObjectId("549b29c970b452eeb6acecdd")
},
{
"_id" : ObjectId("549b29c970b452eeb6acece9")
},
{
"_id" : ObjectId("549b29c970b452eeb6acecea")
},
{
"_id" : ObjectId("549b995b70b452eeb6acecf9")
},
{
"_id" : ObjectId("549b999470b452eeb6acecfa")
},
{
"_id" : ObjectId("549b9ab670b452eeb6acecfb")
}
],
"startDate" : "2013-10-01"
},
{
"description" : "",
"endDate" : "2013-10-01",
"name" : "Another Company",
"skills" : [
{
"_id" : ObjectId("549b29c970b452eeb6acecd4")
},
{
"_id" : ObjectId("549b29c970b452eeb6acecd5")
},
{
"_id" : ObjectId("549b29c970b452eeb6acecdb")
},
{
"_id" : ObjectId("549b29c970b452eeb6acecdd")
},
{
"_id" : ObjectId("549b29c970b452eeb6acece1")
},
{
"_id" : ObjectId("549b29c970b452eeb6acece9")
},
{
"_id" : ObjectId("549b995b70b452eeb6acecf9")
}
],
"startDate" : "2012-04-01"
},
.....
What I am trying to do is resolve that data I can list the actual skill names under "skills" instead of just object ID's. For reference here's the skills collection:
/* 0 */
{
"_id" : ObjectId("549b29c970b452eeb6acecd4"),
"name" : "CSS",
"description" : ""
}
/* 1 */
{
"_id" : ObjectId("549b29c970b452eeb6acecd5"),
"name" : "HTML5",
"description" : ""
}
/* 2 */
{
"_id" : ObjectId("549b29c970b452eeb6acecd6"),
"name" : "Ruby",
"description" : ""
}
/* 3 */
{
"_id" : ObjectId("549b29c970b452eeb6acecd7"),
"name" : "Ruby on Rails",
"description" : ""
}
I've tried looking into using MapReduce to do some kind of join, but I can barely wrap my head around it and all the examples I'm finding don't have data this complex.
What's the best approach for getting my desired result? Side note: I'm not 100% sure that simply embedding the skills in the "skills" property is the right approach. I'm trying to keep them separate because the skills may be listed in other areas of my application separate from work history.