My controller:
#RequestMapping(value = "/{id}/giveFacilitiesAccess", method = RequestMethod.POST)
public Object giveFacilityAccessToAnotherUser(#PathVariable("id") String userId)
{
return userService.giveFacilitiesAccessToAnotherUser(userId);
}
My service:
#Override
public Object giveFacilitiesAccessToAnotherUser(String id)
{
String userId = getLoggedInUserId();
User u = userDao.findById(userId);
List<String> facilitiesAccess = u.getFacilitiesAccess();
return userDao.giveFacilitiesAccessToAnotherUser(id,facilitiesAccess);
}
My dao:
#Override
public Object giveFacilitiesAccessToAnotherUser(String userId, List<String>facilitiesAccess)
{
Query query = new Query();
query.addCriteria(Criteria.where("id").is(userId));
Update update = new Update().addToSet("facilitiesAccess.",facilitiesAccess);
mongoTemplate.updateFirst(query, update, User.class);
return null;
}
After updating:
"facilitiesAccess":["5f0996f792691d1b68671da3",["5f0998ba92691d1b68671da4"]]
It's updating like array inside another array, but i need in this format:
"facilitiesAccess":["5f0996f792691d1b68671da3","5f0998ba92691d1b68671da4"]
The update works with the syntax using the addToSet(String key) which returns a Update.AddToSetBuilder - then apply the each(Object... values) method on the builder, to return the Update object.
Update update = new Update().addToSet("facilitiesAccess").each(facilitiesAccess);
You need to use Each like below
#Override
public Object giveFacilitiesAccessToAnotherUser(String userId, List<String>facilitiesAccess)
{
Query query = new Query();
query.addCriteria(Criteria.where("id").is(userId));
Update update = new Update().addToSet("facilitiesAccess.",new Each(facilitiesAccess));
mongoTemplate.updateFirst(query, update, User.class);
return null;
}
Related
I am having trouble figuring out how to pass a parameter to a query. In this case, I want to get a user by name field. I know I can pass an id, but how do I pass another field? Do I need to create a secondary index?
private AWSAppSyncClient mAWSAppSyncClient;
mAWSAppSyncClient.query(GetUserQuery.builder().build())
.responseFetcher(AppSyncResponseFetchers.CACHE_AND_NETWORK)
.enqueue(userCallback);
query GetUser($id: ID!) {
getUser(id: $id) {
id
userId
name
...
}
}
Use ListUsers (ListXXXX) to query with multiple parameters.
Example - query by name = "aaa":
ModelStringFilterInput modelStringFilterInput = ModelStringFilterInput.builder().eq("aaa").build();
ModelUserFilterInput modelUserFilterInput = ModelUserFilterInput.builder().name(modelStringFilterInput).build();
mAWSAppSyncClient.query(ListUsersQuery.builder().filter(modelUserFilterInput).build())
.responseFetcher(AppSyncResponseFetchers.CACHE_AND_NETWORK)
.enqueue(userCallback);
private GraphQLCall.Callback<ListUsersQuery.Data> userCallback = new GraphQLCall.Callback<ListUsersQuery.Data>() {
#Override
public void onResponse(#Nonnull Response<ListUsersQuery.Data> response) {
Log.d(TAG, response.data().listUsers().items().toString());
}
#Override
public void onFailure(#Nonnull ApolloException e) {
Log.d(TAG, e.toString());
}
};
I'm using this method to send multiple list to client.
public ResponseEntity<?> getFiveLastRequestOfEachVehicleType() {
ResponseContent content = getResponseContent();
Map<String, List<Request>> map = new HashMap<>();
GroupBy groupBy = new GroupBy();
groupBy.initialDocument("vehicleTypeEnum");
query = new Query();
queryFieldsFilterLastFiveRequest(query, VehicleTypeEnum.NEISAN);
map.put("NEISAN", mongoOperations.find(query, Request.class));
query = new Query();
queryFieldsFilterLastFiveRequest(query, VehicleTypeEnum.BADSAN);
map.put("BADSAN", mongoOperations.find(query, Request.class));
query = new Query();
queryFieldsFilterLastFiveRequest(query, VehicleTypeEnum.BUJE);
map.put("BUJE", mongoOperations.find(query, Request.class));
content.setData(map);
return getReturn(content);
}
And this method apply criteria to each query
private void queryFieldsFilterLastFiveRequest(Query query, VehicleTypeEnum vehicleTypeEnum) {
query.addCriteria(Criteria.where("vehicleTypeEnum").is(vehicleTypeEnum));
query.addCriteria(Criteria.where("unlock").is(true));
query.fields()
.include("id")
.include("goodsTypeTitle")
.include("originCityTitle")
.include("price");
query.limit(5);
}
I wonder if there is any way to retrieve all list in one request to database using MongoOperations.
I would go to grouping manually later on, first query for all vehicleType :
private void queryFieldsFilterLastFiveRequest(Query query, VehicleTypeEnum... vehicleTypeEnum..) {
query.addCriteria(Criteria.where("vehicleTypeEnum").in(vehicleTypeEnum));
query.addCriteria(Criteria.where("unlock").is(true));
query.fields()
.include("id")
.include("goodsTypeTitle")
.include("originCityTitle")
.include("price");
query.limit(5);
}
Here the is has been changed by in, and accept a list of VehicleTypeEnum
Then to use it :
public ResponseEntity<?> getFiveLastRequestOfEachVehicleType() {
ResponseContent content = getResponseContent();
Map<String, List<Request>> map;
query = new Query();
queryFieldsFilterLastFiveRequest(query, VehicleTypeEnum.NEISAN, VehicleTypeEnum.BADSAN, VehicleTypeEnum.BUJE);
map = mongoOperations.find(query, Request.class).stream()
.collect(Collectors.toMap(r -> r.getVehicleTypeEnum().name(),r -> r));
content.setData(map);
return getReturn(content);
}
Here i use the stream api to group result by VehiculeTypeEnum name
I am trying to do a multiple insert using the camel mongo db component.
My Pojo representation is :
Person {
String firstName;
String lastName;
}
I have a processor which constructs a valid List of Person pojo and is a valid json structure.
When this list of Person is sent to the mongodb producer , on invocation of createDoInsert the type conversion to BasicDBObject fails. This piece of code below looks to be the problem. Should it have more fall backs / checks in place to attempt the list conversion down further below as it fails on the very first cast itself. Debugging the MongoDbProducer the exchange object being received is a DBList which extends DBObject. This causes the singleInsert flag to remain set at true which fails the insertion below as we get a DBList instead of a BasicDBObject :
if(singleInsert) {
BasicDBObject insertObjects = (BasicDBObject)insert;
dbCol.insertOne(insertObjects);
exchange1.getIn().setHeader("CamelMongoOid", insertObjects.get("_id"));
}
The Camel MongoDbProducer code fragment
private Function<Exchange, Object> createDoInsert() {
return (exchange1) -> {
MongoCollection dbCol = this.calculateCollection(exchange1);
boolean singleInsert = true;
Object insert = exchange1.getIn().getBody(DBObject.class);
if(insert == null) {
insert = exchange1.getIn().getBody(List.class);
if(insert == null) {
throw new CamelMongoDbException("MongoDB operation = insert, Body is not conversible to type DBObject nor List<DBObject>");
}
singleInsert = false;
insert = this.attemptConvertToList((List)insert, exchange1);
}
if(singleInsert) {
BasicDBObject insertObjects = (BasicDBObject)insert;
dbCol.insertOne(insertObjects);
exchange1.getIn().setHeader("CamelMongoOid", insertObjects.get("_id"));
} else {
List insertObjects1 = (List)insert;
dbCol.insertMany(insertObjects1);
ArrayList objectIdentification = new ArrayList(insertObjects1.size());
objectIdentification.addAll((Collection)insertObjects1.stream().map((insertObject) -> {
return insertObject.get("_id");
}).collect(Collectors.toList()));
exchange1.getIn().setHeader("CamelMongoOid", objectIdentification);
}
return insert;
};
}
My route is as below :
<route id="uploadFile">
<from uri="jetty://http://0.0.0.0:9886/test"/>
<process ref="fileProcessor"/>
<unmarshal>
<csv>
<header>fname</header>
<header>lname</header>
</csv>
</unmarshal>
<process ref="mongodbProcessor" />
<to uri="mongodb:mongoBean?database=axs175&collection=insurance&operation=insert" />
and the MongoDBProcessor constructing the List of Person Pojo
#Component
public class MongodbProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
ArrayList<List<String>> personlist = (ArrayList) exchange.getIn().getBody();
ArrayList<Person> persons = new ArrayList<>();
for(List<String> records : personlist){
Person person = new Person();
person.setFname(records.get(0));
person.setLname(records.get(1));
persons.add(person);
}
exchange.getIn().setBody(persons);
}
}
Also requested information here - http://camel.465427.n5.nabble.com/Problems-with-MongoDbProducer-multiple-inserts-tc5792644.html
This issue is now fixed via - https://issues.apache.org/jira/browse/CAMEL-10728
I'm recently implemented ShardIdentifierProvider. It is working fine. But how to ensure it is using only one shared for query?
public class SiteIdAsShardIdProvider extends ShardIdentifierProviderTemplate {
#Override
protected Set<String> loadInitialShardNames(Properties properties, BuildContext buildContext) {
ServiceManager serviceManager = buildContext.getServiceManager();
SessionFactory sessionFactory = serviceManager.requestService(HibernateSessionFactoryServiceProvider.class, buildContext);
Session session = sessionFactory.openSession();
try {
#SuppressWarnings("unchecked")
List<String> ids = session.createSQLQuery("select cast(id as CHAR(3)) from website").list();
return new HashSet<>(ids);
} finally {
session.close();
}
}
#Override
public String getShardIdentifier(Class<?> entityType, Serializable id, String idAsString, Document document) {
return document.getFieldable("siteId").stringValue();
}
}
Creating your own custom filter and overriding getShardIdentifiersForQuery should do the trick. Here is something that does approximately the same as what's in the documentation, but with a ShardIdentifierProviderTemplate:
#Override
public Set<String> getShardIdentifiersForQuery(FullTextFilterImplementor[] filters) {
FullTextFilter filter = getFilterByName( filters, "customer" );
if ( filter == null ) {
return getAllShardIdentifiers();
}
else {
Set<String> result = new HashSet<>();
result.add( filter.getParameter( "customerID" ) );
return result;
}
}
private FullTextFilter getFilterByName(FullTextFilterImplementor[] filters, String name) {
for ( FullTextFilterImplementor filter: filters ) {
if ( filter.getName().equals( name ) ) {
return filter;
}
}
return null;
}
I created a ticket to update the documentation: https://hibernate.atlassian.net/browse/HSEARCH-2513
The shard selection at query time is controlled by using a custom Filter.
See "5.3.1. Using filters in a sharded environment" for details and examples.
I have a simple problem storing and retrieving an embedded collection of entity to mongo. I have checked theses question :
how to serialize class? and Mongodb saves list of object
what I understand is to save a list objects the class of that objects must extends ReflactionDBObject. This worked for saving the object, by retrieving it with the embedded collection does not work.
here a simple test show that retrieving embedded entities does not work !
#Test
public void whatWasStoredAsEmbeddedCollectionIsRetrieved2() {
BasicDBObject country = new BasicDBObject();
country.put("name", "Bulgaria");
List<City> cities = Lists.newArrayList(new City("Tarnovo"));
country.put("listOfCities", cities);
DBCollection collection = db().get().getCollection("test_Collection");
collection.save(country);
DBCursor object = collection.find(new BasicDBObject().append("name", "Bulgaria"));
DBObject returnedCity = object.next();
DBObject embeddedCities = (DBObject) returnedCity.get("listOfCities");
System.out.println(embeddedCities);
}
Here is the City Class
class City extends ReflectionDBObject {
String name;
City() {
}
City(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof City)) return false;
City city = (City) o;
if (name != null ? !name.equals(city.name) : city.name != null) return false;
return true;
}
#Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
#Override
public String toString() {
return "City{" +
"name='" + name + '\'' +
'}';
}
}
The out put of the System.out.println statement is [ { "_id" : null }]
Now how can get back the embedded object and the embedded list in it ?
If you do not have a requirement to define your own class City, you can define subdocuments using the BasicDBObjects. I only added the 'name' field to the citySubDoc1 and citySubDoc2, but of course, you can add more fields to these subdocuments.
// Define subdocuments
BasicDBObject citySubDoc1 = new BasicDBObject();
citySubDoc1.put("name", "Tarnovo");
BasicDBObject citySubDoc2 = new BasicDBObject();
citySubDoc2.put("name", "Sofia");
// add to list
List<DBObject> cities = new ArrayList <DBObject>();
cities.add(citySubDoc1);
cities.add(citySubDoc2);
country.put("listOfCities", cities);
collection.save(country);
// Specify query condition
BasicDBObject criteriaQuery = new BasicDBObject();
criteriaQuery.put("name", "Bulgaria");
// Perform the read
DBCursor cursor = collection.find(criteriaQuery);
// Loop through the results
try {
while (cursor.hasNext()) {
List myReturnedListOfCities = (List) cursor.next().get("listOfCities");
System.out.println(myReturnedListOfCities);
}
} finally {
cursor.close();
}