How to add two fields in mongoDB using java driver - mongodb-java

db.student.aggregate([{$project:{rollno:1,per:{$divide:[{$add:["marks1","$marks2","$marks3"]},3]}}}])
how to write this query in java????? here,student is collection with fields rollno,name and marks and i have to find the percentage of the students according to their roll numbers . I am not able to write code for adding their marks as add operator does not support multiple value's for addition.

This seems to work. There are other builder pattern/conveniences but this exposes all the workings. And leaves room for rich dynamic construction.
DBCollection coll = db.getCollection("student");
List<DBObject> pipe = new ArrayList<DBObject>();
/**
* Clearly, lots of room for dynamic behavior here.
* Different sets of marks, etc. And the divisor is
* the length of these, etc.
*/
String[] marks = new String[]{"$marks1","$marks2","$marks3"};
DBObject add = new BasicDBObject("$add", marks);
List l2 = new ArrayList();
l2.add(add);
l2.add(marks.length); // 3
DBObject divide = new BasicDBObject("$divide", l2);
DBObject prjflds = new BasicDBObject();
prjflds.put("rollno", 1);
prjflds.put("per", divide);
DBObject project = new BasicDBObject();
project.put("$project", prjflds);
pipe.add(project);
AggregationOutput agg = coll.aggregate(pipe);
for (DBObject result : agg.results()) {
System.out.println(result);
}

Related

Problem in adding multi filter to odata service

I have the following code. I am trying to read 3 different values for PO from input fields then displaying the result in list. Program is working fine for single input but for multiple inputs i am facing issues.
var oV1 = this.getView().byId("oInput").getValue();
var oV2 = this.getView().byId("oInput1").getValue();
var oV3 = this.getView().byId("oInput2").getValue();
var oFilter = [new sap.ui.model.Filter("Ebeln", sap.ui.model.FilterOperator.Contains, oV1)];
var oFilter1 = [new sap.ui.model.Filter("Ebeln", sap.ui.model.FilterOperator.Contains, oV2)];
var oFilter2 = [new sap.ui.model.Filter("Ebeln", sap.ui.model.FilterOperator.Contains, oV3)];
var orFilter =new Array(new sap.ui.model.Filter({filters:[oFilter, oFilter1, oFilter2],and:true}));
var oView1 = this.getView();
var oTable = oView1.byId("myTable");
var oBinding = oTable.getBinding("items");
if(oV1 === "")
{
oBinding.filter( [] );
oBinding.refresh(true);
}
else
{
oBinding.filter(orFilter);
At the above oBinding.filter I am receiving following error.
Filter in Aggregation of Multi filter has to be instance of sap.ui.model.Filter -
Unable to get property 'replace' of undefined or null reference
Please help.
You wrapped your filters in 1000 layers of Arrays which doesn't make sense.
Just create a single array which contains Filter objects:
// Filter, FilterOperator, and FilterType required from "sap/ui/model/*"
const aFilter = [
new Filter("Ebeln", FilterOperator.Contains, sV1),
new Filter("Ebeln", FilterOperator.Contains, sV2),
new Filter("Ebeln", FilterOperator.Contains, sV3),
];
oListBinding.filter(aFilter, FilterType.Application);
I know this isn't a code review but some suggestions:
No one uses new Array(). Just use [].
Also you used Hungarian notation but every one of your variable names begins with o. o means object. Some of your variables are not objects but strings (like oV1, better would be sV1) or arrays.
For the filters aggregation, sap.ui.model.Filter accepts a Filter[]. But because oFilter already is a Filter[], [oFilter, oFilter1, oFilter2] is a Filter[][], so that won't work.
To make it work, just remove the surrounding [] from the filter definitions, like so:
var oFilter = new Filter(...);.

Sorting large amount of strings and grouping

I'm trying to find a set of unique strings and break it up into disjoint groups by criterium: if two strings have coincidence at 1 or more columns, it belongs to one group.
For example
111;123;222
200;123;100
300;;100
All of them are belong to one group, cause of overlap at:
first string with second by "123" value
second string with third by "100" value
After getting these groups, I need to save them to a text file.
I got 60 MB file with strings, which should be sorted.(time limit: 30 sec)
I think. First, the best way is to divide strings into columns, and then try to find any coincidence, but I'm not sure at all.
Please, help me to find the solution.
For now, I have this code; it works about 2.5-3 sec:
// getting from file
File file = new File(path);
InputStream inputFS = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(inputFS));
List<String> inputList = br.lines().collect(Collectors.toList());
br.close();
List<String> firstValues = new ArrayList<>();
List<String> secondValues = new ArrayList<>();
List<String> thirdValues = new ArrayList<>();
// extracting distinct values and splitting
final String qq = "\"";
inputList.stream()
.map(s -> s.split(";"))
.forEach(strings -> {
firstValues.add(strings.length > 0 ? strings[0].replaceAll(qq, "") : null);
secondValues.add(strings.length > 1 ? strings[1].replaceAll(qq, "") : null);
thirdValues.add(strings.length > 2 ? strings[2].replaceAll(qq, "") : null);
});
// todo: add to maps by the row and then find groups

Java8 stream average of object property in collection

I'm new to Java so if this has already been answered somewhere else then I either don't know enough to search for the correct things or I just couldn't understand the answers.
So the question being:
I have a bunch of objects in a list:
try(Stream<String> logs = Files.lines(Paths.get(args))) {
return logs.map(LogLine::parseLine).collect(Collectors.toList());
}
And this is how the properties are added:
LogLine line = new LogLine();
line.setUri(matcher.group("uri"));
line.setrequestDuration(matcher.group("requestDuration"));
....
How do I sort logs so that I end up with list where objects with same "uri" are displayed only once with average requestDuration.
Example:
object1.uri = 'uri1', object1.requestDuration = 20;
object2.uri = 'uri2', object2.requestDuration = 30;
object3.uri = 'uri1', object3.requestDuration = 50;
Result:
object1.uri = 'uri1', 35;
object2.uri = 'uri2', 30;
Thanks in advance!
Take a look at Collectors.groupingBy and Collectors.averagingDouble. In your case, you could use them as follows:
Map<String, Double> result = logLines.stream()
.collect(Collectors.groupingBy(
LogLine::getUri,
TreeMap::new,
Collectors.averagingDouble(LogLine::getRequestDuration)));
The Collectors.groupingBy method does what you want. It is overloaded, so that you can specify the function that returns the key to group elements by, the factory that creates the returned map (I'm using TreeMap here, because you want the entries ordered by key, in this case the URI), and a downstream collector, which collects the elements that match the key returned by the first parameter.
If you want an Integer instead of a Double value for the averages, consider using Collectors.averagingInt.
This assumes LogLine has getUri() and getRequestDuration() methods.

Most efficient way to determine if there are any differences between specific properties of 2 lists of items?

In C# .NET 4.0, I am struggling to come up with the most efficient way to determine if the contents of 2 lists of items contain any differences.
I don't need to know what the differences are, just true/false whether the lists are different based on my criteria.
The 2 lists I am trying to compare contain FileInfo objects, and I want to compare only the FileInfo.Name and FileInfo.LastWriteTimeUtc properties of each item. All the FileInfo items are for files located in the same directory, so the FileInfo.Name values will be unique.
To summarize, I am looking for a single Boolean result for the following criteria:
Does ListA contain any items with FileInfo.Name not in ListB?
Does ListB contain any items with FileInfo.Name not in ListA?
For items with the same FileInfo.Name in both lists, are the FileInfo.LastWriteTimeUtc values different?
Thank you,
Kyle
I would use a custom IEqualityComparer<FileInfo> for this task:
public class FileNameAndLastWriteTimeUtcComparer : IEqualityComparer<FileInfo>
{
public bool Equals(FileInfo x, FileInfo y)
{
if(Object.ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
return x.FullName.Equals(y.FullName) && x.LastWriteTimeUtc.Equals(y.LastWriteTimeUtc);
}
public int GetHashCode(FileInfo fi)
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 23 + fi.FullName.GetHashCode();
hash = hash * 23 + fi.LastWriteTimeUtc.GetHashCode();
return hash;
}
}
}
Now you can use a HashSet<FileInfo> with this comparer and HashSet<T>.SetEquals:
var comparer = new FileNameAndLastWriteTimeUtcComparer();
var uniqueFiles1 = new HashSet<FileInfo>(list1, comparer);
bool anyDifferences = !uniqueFiles1.SetEquals(list2);
Note that i've used FileInfo.FullName instead of Name since names aren't unqiue at all.
Sidenote: another advantage is that you can use this comparer for many LINQ methods like GroupBy, Except, Intersect or Distinct.
This is not the most efficient way (probably ranks a 4 out of 5 in the quick-and-dirty category):
var comparableListA = ListA.Select(a =>
new { Name = a.Name, LastWrite = a.LastWriteTimeUtc, Object = a});
var comparableListB = ListB.Select(b =>
new { Name = b.Name, LastWrite = b.LastWriteTimeUtc, Object = b});
var diffList = comparableListA.Except(comparableListB);
var youHaveDiff = diffList.Any();
Explanation:
Anonymous classes are compared by property values, which is what you're looking to do, which led to my thinking of doing a LINQ projection along those lines.
P.S.
You should double check the syntax, I just rattled this off without the compiler.

Subsonic Syntax Question (with GroupBy)

Is there a way to do this :
SubSonic.Where filter = new SubSonic.Where();
filter.ColumnName = Region.Columns.Region;
filter.Comparison = SubSonic.Comparison.IsNot;
filter.ParameterValue = null;
SubSonic.Aggregate orderBy = new SubSonic.Aggregate(Region.Columns.RegionName, SubSonic.AggregateFunction.GroupBy);
RegionCollection regions = new RegionCollection().Where(filter).GroupBy(groupBy).Load();
The "GroupBy" part in the last line doesn't compile... (I'm using SubSonic 2.1)
Just in case there isn't a reason you need the old Where construct:
SubSonic.Aggregate groupBy = new SubSonic.Aggregate(Region.Columns.RegionName, SubSonic.AggregateFunction.GroupBy);
RegionCollection regions = new SubSonic.Select(groupBy).From(Region.Schema).Where(Region.RegionColumn).IsNotNull().ExecuteAsCollection<RegionCollection>();
With Collections you can use OrderByAsc and OrderByDesc but they both only allow passing a string as a parameter. And the SubSonic.AggregateFunction.GroupByprobably isn't what you want.
Try this instead:
var result = new RegionCollection().OrderByAsc(Region.Columns.RegionName).Load();

Resources