How to do OR inside of AND? - mongodb

SQL query=>
where and ((subtype="dailyMessage" and registDate="today") or(subtype !="dailyMessage"))
i want to retrive this query by using mongodb.
i have this collection. (today is '2017-08-16T15:48:19.947Z')
{
"_id" : ObjectId("597768443b1fd6308c0350c0"),
"type" : "message",
"subtype" : "dailyMessage",
"message" : test1",
"registDate" : ISODate("2017-08-16T15:48:19.947Z")
},
{
"_id" : ObjectId("597768443b1fd6308c0350c1"),
"type" : "message",
"subtype" : "dailyPush",
"message" : test2",
"registDate" : ISODate("2017-07-25T15:48:19.947Z")
},
{
"_id" : ObjectId("597768443b1fd6308c0350c2"),
"type" : "message",
"subtype" : "dailyPush",
"message" : test3",
"registDate" : ISODate("2017-07-24T15:48:19.947Z")
}
here is my code(spring boot mongodb , using java 8)
List<String> listOfmessage = new ArrayList<String>();
listOfSubtype.add("dailyMessage");
criteria = Criteria.where("test").is("james");
criteria.andOperator(Criteria.where("registDate").gte(LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT)).lte(LocalDateTime.now()) , Criteria.where("subtype").in(listOfmessage) .orOperator(Criteria.where("subtype").nin(listOfmessage)));
my problem is that how can i insert orOperator on the andOperator?

As mentioned in the comment, the and outside the whole condition doesn't make sense. The below code is written for the following condition.
(condition1 AND condition2) OR condition3
Code:-
You may need to alter the below code to get the MongoOperations object based on your Spring configuration.
"register" is the collection name. You can change it accordingly as per your collection name.
public Boolean getRegisterData() {
MongoOperations mongoOperations = getMongoConnection();
List<String> listOfSubType = new ArrayList<String>();
listOfSubType.add("dailyMessage");
List<String> listOfMessage = new ArrayList<String>();
listOfMessage.add("test1");
Criteria criteriaSubTypeAndDate = new Criteria();
criteriaSubTypeAndDate.andOperator(Criteria.where("registDate")
.gte(LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT)).lte(LocalDateTime.now()),
Criteria.where("subtype").in(listOfSubType));
Criteria criteriaSubType = Criteria.where("subtype").ne("dailyMessage");
Criteria criteriaFull = new Criteria();
criteriaFull.orOperator(criteriaSubTypeAndDate, criteriaSubType);
Query query = new Query();
query.addCriteria(criteriaFull);
System.out.println(query);
mongoOperations.executeQuery(query, "register", new RegistryDocumentCallbackHandler());
return true;
}
Result set document processing class:-
processDocument() method will get executed for each document in the result set.
public class RegistryDocumentCallbackHandler implements DocumentCallbackHandler {
#Override
public void processDocument(DBObject dbObject) throws MongoException, DataAccessException {
System.out.println("Registry collections data ===>" + dbObject.toString());
}
}

Related

How to get MongoDB entries in date range including limits?

In a Mongo DB, I have the below entries:
> db.DomainObjects.find()
// [...]
{ "_id" : ObjectId("6..3"), "lev" : 7, "date" : ISODate("2021-02-01T00:00:00Z"), "val" : 29.1 }
{ "_id" : ObjectId("6..4"), "lev" : 7, "date" : ISODate("2021-02-02T00:00:00Z"), "val" : 20.3 }
{ "_id" : ObjectId("6..5"), "lev" : 7, "date" : ISODate("2021-02-05T00:00:00Z"), "val" : 15.8 }
// [...]
In a ASP.NET Core Service class, I have a reference to the collection using the Mongo DB driver with the below version installed:
Here is how the reference is created:
public DomainService(IDomainDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
_repo = database.GetCollection<Domain>(settings.DomainCollectionName);
}
Then I'd like to get the entries by DateTime range (including the limits) using the following method:
public List<Domain> Get(int lev, DateTime dateFrom, DateTime dateTo) {
Expression<Func<Domain, bool>> expr = entry => (entry.lev == lev) &&
(entry.date.CompareTo(dateFrom) >= 0) &&
(entry.date.CompareTo(dateTo) <= 0);
return _repo.Find(expr).ToList();
I use the following GET request:
https://localhost:45645/api/DomainObjects/7/?dateFrom=2021-02-01&dateTo=2021-02-02
However, I only get the entries starting and including the lower limit, the entry on the upper limit is excluded.
For completeness, the controller is this:
[HttpGet("{lev:int}")]
public ActionResult<List<Domain>> Get(int lev, [FromQuery] DateTime? dateFrom = null, [FromQuery] DateTime? dateTo = null) {
if (!dateFrom.HasValue) {
dateFrom = DateTime.MinValue;
return _domainService.Get(lev, (DateTime) dateFrom, (DateTime) dateTo);
}
if (!dateTo.HasValue) {
dateTo = DateTime.Today;
return _domainService.Get(lev, (DateTime) dateFrom, (DateTime) dateTo);
}
return _domainService.Get(lev, (DateTime) dateFrom, (DateTime) dateTo);
}
If the lower limit dateFrom is omitted in the request, it should start with the earliest entry, if the limit dateTo is omitted, it should return all values from dateFrom up until and including today.

Specify multiple criteria's in spring mongo db query

I am iterating over a list of key/value pairs and executing find for each key/value. Can I create a single query document to be kind of union in sql, So that there will be only one database call.
List<User> userList = new ArrayList<User>();
for (Map accounts:attributes) {
Query query = new Query();
List<Criteria> andCriteriaList = new ArrayList<Criteria>();
accounts.forEach((key, value) -> {
Criteria criteria = Criteria.where((String) key).is(value);
andCriteriaList.add(criteria);
});
query.addCriteria(new Criteria().andOperator(andCriteriaList.toArray(new Criteria[andCriteriaList.size()])));
if (mongoTemplate.exists(query, User.class)) {
userList.add((User)mongoTemplate.find(query, User.class));
//System.out.println(mongoTemplate.find(query, User.class));
}
Thanks,
You can refactor your code to create $or expressions. No explicit $and operator needed.
Something like
Query orQuery = new Query();
Criteria orCriteria = new Criteria();
List<Criteria> orExpression = new ArrayList<>();
for (Map<String, Object> accounts : attributes) {
Criteria expression = new Criteria();
accounts.forEach((key, value) -> expression.and(key).is(value));
orExpression.add(expression);
}
orQuery.addCriteria(orCriteria.orOperator(orExpression.toArray(new Criteria[orExpression.size()])));
List<User> userList = mongoOperations.find(orQuery, User.class);
This should output query like
{ "$or" : [{ "key1" : "value1", "key2" : "value2" }, { "key3" : "value3", "key4" : "value4" }] }
if you want to query multiple fields(field1, field2, ....) with values below is the solution
Query query = new Query();
List<Criteria> criteria = new ArrayList<>();
criteria.add(Criteria.where(field1).is(field1val));
criteria.add(Criteria.where(field2).is(field2val));
// you can add all your fields here as above
query.addCriteria(new Criteria().andOperator(criteria.toArray(new Criteria[criteria.size()])));
List<JSONObject> filteredVals = mongoOperations.find(query, JSONObject.class);
the above return filteredVals is JSONObject

how call synchronous mongo query in node js

I have to mongodb collection.
first i will call to coll1 and get ids.Then I want to call coll2 and search by ids and some other fields.
when I am calling to funtion it is returing undefined.
how I can wait untill i m not get result from funtion.
coll1 docs sample:
{
"_id" : ObjectId(""),
"container_id" : "56867887fdb391ff09d15e9",
"item_state" : [
{
"user_id" : 1,
"username" : "x",
"state" : "1"
},
{
"user_id" : 2,
"username" : "y",
"state" : "3"
}
],
"name" : "members test"
}
enter code here
function listMyWorkitems(user_id,callback) {
var user_id=1;
var workItemList = new Array();
db.collection('containers').find({'start_date':{"$lt":new Date(2017,02,11)}}).toArray(function(err,docs){
console.log("doc length");
console.log(docs.length);
for (var i = 0; i < docs.length; i++) {
db.collection('work_items').find({"$and":[{'container_id':docs[i]._id.toString()},{'item_state':{"$elemMatch":{'user_id':user_id,'is_active':1,'state':{"$in":["1","2","3"]}}}}]}).toArray(function(err,workDocs){
//console.log(workDocs);
for (var i = 0; i < workDocs.length; i++) {
for (var j = 0; j < workDocs[i].item_state.length; j++) {
var doc=workDocs[i].item_state[j]
workItemList.push(workDocs[i].name)
}
}
});
}
callback(workItemList);
});
}
listMyWorkitems(user_id,funtion(err,workItemList) {
console.log(workItemList)
});
I understand async auto concept but still it is returning empty list
here is code what i tried till now.. i done for collection 1 but once it is solve then i can query to collection 2 also..
var async = require('async');
var mongojs = require("mongojs");
var db = mongojs("localhost/mc_dev");
async.auto({
coll1task: function(callback) {
var idlist =[];
console.log("ids fetch from collection 1");
db.collection('containers').find({'start_date':{"$lt":new Date(2017,02,11)}}).toArray(function(err,docs){
docs.forEach(function(doc){
console.log(doc._id);
idlist.push(doc._id);
});});
callback(null,idlist);
},
finalcontrol: [
'coll1task',
function(results,callback) {
console.log(results.coll1task);
}
],
},
function(error, results) {
console.log('error = ', error)
console.log('results = ', results)
})
The best approach to do things asynchronously in node.js is by using modules like ASYNC or PROMISE.
You can visit async and get access to all the modules provided by this library.
Main modules provided by async library are
async.series=> this is what you can use in your case.
2.async.parallel
async.auto => I will suggest you to use this as it provide you to perform operations asynchronously as well as synchronously
Further more you can also use PROMISES as now they are the part of ECMA SCRIPT 6 there are various modules also which you can use to get this done.

Spring data mongo aggregation mapping to object

I want to map the results of an aggregation to an POJO without iterating through the raw results. The POJO is a field in the Collection on which I'm running the aggregation.
MatchOperation match = match(Criteria.where("drill").is(drill));
SortOperation sort = sort(DESC, "creationDate");
GroupOperation group = group("athlete").first("athlete").as("athlete");
LimitOperation limit = limit(10);
ProjectionOperation project = project("athlete");
Aggregation aggregation = newAggregation(match, sort, group, limit, project);
AggregationResults<Athlete> results = mongoTemplate.aggregate(aggregation, DrillResultInfo.class, Athlete.class);
List<Athlete> mappedResult = results.getMappedResults();
It returns the correct number of objects, but they have as the id the map of the object and the other properties are null.
The result:
id: { "_id" : { "$oid" : "57cd46780348276373579821"} , "_class" : "Athlete" , "firstName" : "Jenny" , "lastName" : "Smith" ....}
The rest of the properties are null.
The Collection:
public class DrillResultInfo {
#Id
private String id;
private Long resultId;
#DBRef
private Athlete athlete;
#DBRef
private Drill drill;
....
}
(.... represents left out data)
Update:
I've made some updates to the code to get it to work:
List<Athlete> respone = new ArrayList<>();
MatchOperation match = match(Criteria.where("drill").is(drill));
SortOperation sort = sort(DESC, "creationDate");
GroupOperation group = group("athlete");
LimitOperation limit = limit(5);
SkipOperation skip = skip(skipElements);
ProjectionOperation project = project("_id");
TypedAggregation<DrillResultInfo> agg = newAggregation(DrillResultInfo.class, match, sort, group, skip, limit, project);
AggregationResults<Object> results = mongoTemplate.aggregate(agg, Object.class);
List<Object> mappedResult = results.getMappedResults();
for (Object obj : mappedResult) {
Athlete ath = (Athlete) ((LinkedHashMap) obj).get("_id");
respone.add(ath);
}
return respone;
I would like to get rid of that for.

Get all dynamic fields of a groovy class

In my application I need to use dynamic fields of a class.
The object is persisted into MongoDB (also dynamically) from json request:
Object obj = new Object()
def objectData = request.JSON.object
for(item in objectData) {
obj[item.key] = item.value
}
obj.save(flush: true)
However, when I am trying to get the objct back from Mongo, this way:
List<Object> objects = Object.list()
def objList = new ArrayList();
def filtered = ['class', 'active', 'metaClass', 'version']
for(obj in objects) {
objList.add(obj.properties)
}
I am getting something like this:
"objects" : [
{
"dbo" : {
"_id" : "531afe54300426462e60c1ce",
"key2" : "val2",
"key3" : "hello",
"version" : 1,
"key1" : "val1"
}
},
...
Of coarse I can take only the "dbo" of every object, and filter what I don't need manually, but it looks wrong. What would be the right way to get all the properties of an object including dynamic ones?
Definition of Object class:
package com.iibs.mongo
class Object {
String id
static mapWith = "mongo"
static constraints = {
}
}
Thanks,