MongoDB - MongoJack find and remove - java

I am completely new to MongoDB and MongoJack.
I have this collection called pbf
{
"_id" : ObjectId("541ea72044ae1b4043e9ccba"),
"name" : "First civ game",
"type" : "WAW",
"numOfPlayers" : 4,
"active" : true,
"players" : [ ],
"civs" : [
{
"objectType" : "civ",
"name" : "Indians",
"used" : false,
"hidden" : true
},
{
"objectType" : "civ",
"name" : "Arabs",
"used" : false,
"hidden" : true
},
{
"objectType" : "civ",
"name" : "Japanese",
"used" : false,
"hidden" : true
},
{
"objectType" : "civ",
"name" : "Egyptians",
"used" : false,
"hidden" : true
},
}
What I want to do "Remove and return one civs item by Id"
I have tried something like this:
protected static JacksonDBCollection<PBF, String> pbfCollection;
BasicDBObject field = new BasicDBObject();
field.put("civs", 1);
field.put("_id", "541ea72044ae1b4043e9ccba");
PBF pbf = pbfCollection.findAndRemove(field)
But this just throws exception saying it doesn't find anything
So bascially I want this returned
{
"objectType" : "civ",
"name" : "Indians",
"used" : false,
"hidden" : true
}
How can I accomplish this?

I solved it using two steps. I am sure though there is a better way of doing it.
//First get, then remove, then update
PBF pbf = pbfCollection.findOneById(pbfId);
Civ civ = pbf.getCivs().remove(0);
pbfCollection.updateById(pbf.getId(), pbf);
This worked, but I think it should be a better way of doing it

Related

Elasticsearch is not working with Alphanumeric

I am having alphanumeric codes like AA111, 111AA, AA-111, AAAA, 1111. Below is the mapping for elastic search
"name" : {
"type" : "text",
"analyzer" : "standard",
"fields" : {
"lower_case_sort" : {
"type" : "keyword",
"normalizer" : "lowercase"
}
},
"copy_to" : "default"
}
The default mapping is like below
"default" : {
"type" : "text",
"analyzer" : "index_ngram",
"search_analyzer" : "search_ngram"
},
When we search with AAA or AA, It returns results. But when we search by 111 it does not return any result.
Below is the query
"bool" : {
"filter" : [
{
"match" : {
"default" : {
"query" : "111",
"operator" : "AND",
"prefix_length" : 0,
"max_expansions" : 50,
"fuzzy_transpositions" : true,
"lenient" : false,
"zero_terms_query" : "NONE",
"auto_generate_synonyms_phrase_query" : true,
"boost" : 1.0
}
}
},
Its happening as you are using the some analyzer on your default field, which is removing the numbers from your text (simple analyzer is one of them), you need to use a tokeniser which doesn't remove them like edge-ngram and search on them, or use the standard analyzer which also works with the numbers.

Elastic termsQuery not giving expected result

I have an index where each of my objects has status field which can have some predefined values. I want to fetch all of them which has statusINITIATED, UPDATED, DELETED, any match with these and hence created this query by java which I got printing on console, using Querybuilder and nativeSearchQuery, executing by ElasticsearchOperations:
{
"bool" : {
"must" : [
{
"terms" : {
"status" : [
"INITIATED",
"UPDATED",
"DELETED"
],
"boost" : 1.0
}
}
],
"adjust_pure_negative" : true,
"boost" : 1.0
}
}
I have data in my index with 'INITIATED' status but not getting anyone with status mentioned in the query. How to fix this query, please?
If you need anything, please let me know.
Update: code added
NativeSearchQueryBuilder nativeSearchQueryBuilder=new NativeSearchQueryBuilder();
QueryBuildersingleQb=QueryBuilders.boolQuery().must(QueryBuilders.termsQuery("status",statusList));
Pageable pageable = PageRequest.of(0, 1, Sort.by(Defs.START_TIME).ascending());
FieldSortBuilder sort = SortBuilders.fieldSort(Defs.START_TIME).order(SortOrder.ASC);
nativeSearchQueryBuilder.withQuery(singleQb);
nativeSearchQueryBuilder.withSort(sort);
nativeSearchQueryBuilder.withPageable(pageable);
nativeSearchQueryBuilder.withIndices(Defs.SCHEDULED_MEETING_INDEX);
nativeSearchQueryBuilder.withTypes(Defs.SCHEDULED_MEETING_INDEX);
NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
List<ScheduledMeetingEntity> scheduledList=elasticsearchTemplate.queryForList(searchQuery, ScheduledMeetingEntity.class);
Update 2: sample data:
I got this from kibana query on this index:
"hits" : [
{
"_index" : "index_name",
"_type" : "type_name",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"createTime" : "2021-03-03T13:09:59.198",
"createTimeInMs" : 1614755399198,
"createdBy" : "user1#domain.com",
"editTime" : "2021-03-03T13:09:59.198",
"editTimeInMs" : 1614755399198,
"editedBy" : "user1#domain.com",
"versionId" : 1,
"id" : "1",
"meetingId" : "47",
"userId" : "129",
"username" : "user1#domain.com",
"recipient" : [
"user1#domain.com"
],
"subject" : "subject",
"body" : "hi there",
"startTime" : "2021-03-04T07:26:00.000",
"endTime" : "2021-03-04T07:30:00.000",
"meetingName" : "name123",
"meetingPlace" : "placeName",
"description" : "sfsafsdafsdf",
"projectName" : "",
"status" : "INITIATED",
"failTry" : 0
}
}
]
Confirm your mapping:
GET /yourIndexName/_mapping
And see if it is valid
Your mapping needs to have keyword for TermsQuery to work.
{
"status": {
"type" "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
ES can automatically do the mapping for you (without you having to do it yourself) when you first push a document. However you probably have finer control if you do the mapping yourself.
Either way, you need to have keyword defined for your status field.
=====================
Alternative Solution: (Case Insensitive)
If you have a Field named (status), and the values you want to search for are (INITIATED or UPDATED, or DELETED).
Then you can do it like this:
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(createStringSearchQuery());
public QueryBuilder createStringSearchQuery(){
QueryStringQueryBuilder queryBuilder = QueryBuilders.queryStringQuery(" INITIATED OR UPDATED OR DELETED ");
queryBuilder.defaultField("status");
return queryBuilder;
}
Printing the QueryBuilder:
{
"query_string" : {
"query" : "INITIATED OR UPDATED OR DELETED",
"default_field" : "status",
"fields" : [ ],
"type" : "best_fields",
"default_operator" : "or",
"max_determinized_states" : 10000,
"enable_position_increments" : true,
"fuzziness" : "AUTO",
"fuzzy_prefix_length" : 0,
"fuzzy_max_expansions" : 50,
"phrase_slop" : 0,
"escape" : false,
"auto_generate_synonyms_phrase_query" : true,
"fuzzy_transpositions" : true,
"boost" : 1.0
}
}

How can we pass a list of JSON object as JSON string in a BDD feature file in Java

Below is my feature file.
Scenario 1: Getting all AppsCount
When we request for all apps then we get 4 apps and the application list is sent json form:
"[
{ '_id' : 'app1', 'Name' : 'App 1', 'Type' : 1, 'Rules' : [ { '_id' : 'Rule1', 'FilterCriteria' : 8 }, { '_id' : 'Rule2', 'FilterCriteria' : 4 } ], 'Email' : 'test#dell.com', 'IsSlackEnabled' : false, 'IsEmailEnabled' : true, 'IsSMSEnabled' : false, 'IsPhoneEnabled' : false, 'IsNonProdEnabled' : false, 'CreatedBy' : 'test#dell.com' },
{ '_id' : 'app2', 'Name' : 'App 2', 'Type' : 2, 'Rules' : [ { '_id' : 'Rule3', 'FilterCriteria' : 8 } ], 'Email' : 'test1#dell.com', 'IsSlackEnabled' : true, 'SlackChannel' : 'testChannel', 'IsEmailEnabled' : false, 'IsSMSEnabled' : false, 'IsPhoneEnabled' : true, 'IsNonProdEnabled' : false, 'CreatedBy' : 'test1#dell.com' },
{ '_id' : 'app3', 'Name' : 'App 3', 'Type' : 3, 'Rules' : [ { '_id' : 'Rule4', 'FilterCriteria' : 7 } ], 'Email' : 'test3#dell.com', 'IsSlackEnabled' : true, 'IsEmailEnabled' : false, 'SlackChannel' : 'testChannel2', 'IsSMSEnabled' : true, 'IsPhoneEnabled' : false, 'IsNonProdEnabled' : false, 'CreatedBy' : 'test3#dell.com' },
{ '_id' : 'app4', 'Name' : 'App 4', 'Type' : 1, 'Rules' : [], 'Email' : 'test4#dell.com', 'IsSlackEnabled' : false, 'IsEmailEnabled' : false, 'IsSMSEnabled' : false, 'IsPhoneEnabled' : true, 'IsNonProdEnabled' : false, 'CreatedBy' : 'test4#dell.com' }
]"
But this is giving issue, as we need double quotes when writing a json string
So I tried the below feature file.
Scenario 2: Getting all AppsCount
When we request for All Apps then we get 4 apps and the application list is sent json form:
"[
{ "_id" : "app1", "Name" : "App 1", "Type" : 1, "Rules" : [{ "_id" : "Rule1", "FilterCriteria" : 8 }, { "_id" : "Rule2", "FilterCriteria" : 4 } ], "Email" : "test#dell.com", "IsSlackEnabled" : false, "IsEmailEnabled" : true, "IsSMSEnabled" : false, "IsPhoneEnabled" : false, "IsNonProdEnabled" : false, "CreatedBy" : "test#dell.com" },
{ "_id" : "app2", "Name" : "App 2", "Type" : 2, "Rules" : [ { "_id" : "Rule3", "FilterCriteria" : 8 } ], "Email" : "test1#dell.com", "IsSlackEnabled" : true, "SlackChannel" : "testChannel", "IsEmailEnabled" : false, "IsSMSEnabled" : false, "IsPhoneEnabled" : true, "IsNonProdEnabled" : false, "CreatedBy" : "test1#dell.com" },
{ "_id" : "app3", "Name" : "App 3", "Type" : 3, "Rules" : [ { "_id" : "Rule4", "FilterCriteria" : 7 } ], "Email" : "test3#dell.com", "IsSlackEnabled" : true, "IsEmailEnabled" : false, "SlackChannel" : "testChannel2", "IsSMSEnabled" : true, "IsPhoneEnabled" : false, "IsNonProdEnabled" : false, "CreatedBy" : "test3#dell.com" },
{ "_id" : "app4", "Name" : "App 4", "Type" : 1, "Rules" : [], "Email" : "test4#dell.com", "IsSlackEnabled" : false, "IsEmailEnabled" : false, "IsSMSEnabled" : false, "IsPhoneEnabled" : true, "IsNonProdEnabled" : false, "CreatedBy" : "test4#dell.com" }
] "
But when creating a step definition, it comes out with each field's value coming as it's own argument.
I am aware of the
| field1 | field2 |
| value1 | value2 |
solution, but my data is too huge for that and was wondering, if there is a way to pass JSON string directly.
Create a file text.json ..and put json input in the file .. place this file in class path..
IN feature file place the file name in this case- text.json..
in class file stepdef read the filename.... look for the this file in class path..
laod this file using clasloader and use objectmapper to map this json.

MongoDB Java driver - problems with aggregation

In Java with MongoDB driver I want to have pairs (business_name, count), meaning reviews count per business. Currently I have aggregate pipeline:
Bson group = group("$business_id", Accumulators.sum("count", 1));
Bson lookupOperation = lookup(
"business",
"_id",
"business_id",
"business_data"
);
Bson unwind = unwind("$business_data");
Bson project = project(fields(include("business_data.name", "count"), excludeId()));
return db
.getCollection("tip")
.aggregate(Arrays.asList(group, lookupOperation, unwind, project));
It works, but returns:
Document{{count=1, business_data=Document{{name=Firestone Complete Auto Care}}}}
1) How can I unwind business_data.name to have {count, name}?
2) How can I make name distinct? I want only 1 count per name, but printing results gives many identical copies, e. g.:
Document{{count=3, business_data=Document{{name=Malmaison}}}}
Document{{count=3, business_data=Document{{name=Malmaison}}}}
Results are quite big collection, so I return AggregateIterable, but I want results sorted by name. Can I do that with iterable, without loading entire data into array and sorting the array?
EDIT
Business document example:
{
"_id" : ObjectId("5ddbc3c1a94f7aac8d179b7c"),
"business_id" : "vcNAWiLM4dR7D2nwwJ7nCA",
"full_address" : "4840 E Indian School Rd\nSte 101\nPhoenix, AZ 85018",
"hours" : {
"Tuesday" : {
"close" : "17:00",
"open" : "08:00"
},
"Friday" : {
"close" : "17:00",
"open" : "08:00"
},
"Monday" : {
"close" : "17:00",
"open" : "08:00"
},
"Wednesday" : {
"close" : "17:00",
"open" : "08:00"
},
"Thursday" : {
"close" : "17:00",
"open" : "08:00"
}
},
"open" : true,
"categories" : [
"Doctors",
"Health & Medical"
],
"city" : "Phoenix",
"review_count" : 7,
"name" : "Eric Goldberg, MD",
"neighborhoods" : [],
"longitude" : -111.983758,
"state" : "AZ",
"stars" : 3.5,
"latitude" : 33.499313,
"attributes" : {
"By Appointment Only" : true
},
"type" : "business"
}
Review document example:
{
"user_id": "IORZRljfUkedhh1SGMthTA",
"text": "The desserts are enormous..dear god.",
"business_id": "JwUE5GmEO-sH1FuwJgKBlQ",
"likes": 0,
"date": "2011-09-29",
"type": "tip"
}

how to create mongoDB objectid in java

Refering to post How to add an array to a MongoDB document using Java?
I have created a mongo schema using java
it has sub elements, I am getting _id for main document
I would like to get _id in sub elements also here output looks (I have marked the portion where I need _id) b.party.find().pretty();
{
"_id" : ObjectId("5399aba6e4b0ae375bfdca88"),
"addressDetails" : [
{
// _id here
"locationName" : "Office",
"phones" : [
{ // _id here
"name" : "Tel1",
"value" : "95253-"
},
{ // _id here
"name" : "Tel2",
"value" : "95253-"
},
{ // _id here
"name" : "Tel3",
"value" : "95253-"
},
{ // _id here
"name" : "Fax1",
"value" : "0253-"
}
],
"address" : "A-3,MIDCA-3,MIDC",
"defaultBillAddrerss" : "",
"pincode" : "422 010",
"city" : null,
"state" : "1",
"country" : ""
},
{ // _id here
"locationName" : "Factory",
"phones" : [
{ // _id here
"name" : "Tel1",
"value" : "0253-"
},
{ // _id here
"name" : "Tel2",
"value" : "0253-"
},
{ // _id here
"name" : "Tel3",
"value" : "0253-"
},
{ // _id here
"name" : "Fax1",
"value" : "0253-"
}
],
"address" : "A-3 INDUSTRIAL AREA,",
"defaultBillAddrerss" : "",
"pincode" : "422 010",
"city" : null,
"state" : "1",
"country" : ""
}
],
"crLimit" : "0.0",
"crPeriod" : "",
"name" : "CROMPTON GREAVES "
}
Java code to create is similar to How to add an array to a MongoDB document using Java?
Is there any code to create ObjectId("") programmatically in java?
To create objectId programmatically, use the following syntax
import org.bson.types.ObjectId;
ObjectId id1 = new ObjectId();
ObjectId id2 = ObjectId.get();
// In case you want to mention the parent ID itself,
ObjectId id3 = new ObjectId("5399aba6e4b0ae375bfdca88");
To create objectId programmatically, use the following syntax
Map<String,String> objectId = new HashMap<String,String>();
objectId.put("$oid","5399aba6e4b0ae375bfdca88");
Then insert into mongodb.

Categories