how to update just one element of array when updating - mongodb-query

I have a doc like the following:
as you can see I have an array entity: {1,3,4}
Now I want to just change 4 to 10 in that array and update it for that I have the following code:
DBCollection coll = db.getCollection("test");
BasicDBObject newDocument = new BasicDBObject();
BasicDBObject searchQuery = new BasicDBObject().append("time", "20141105230000");
coll.update(searchQuery, newDocument);
String[] str = { "1", "3", "10" };
DBObject updateMatchingElem = new BasicDBObject("$set",
new BasicDBObject().append("entity", str));
coll.update(searchQuery, updateMatchingElem);
But this way is not a good way because I kind of remove entity and then insert the whole array again. Is there anyway that I can just change the one element like 4 to 10?

Now I want to just change 4 to 10 in that array and update it
You can do it in the following way, using the $ positional operator.
//db.collection.update({"entity":4},{$set:{"entity.$":10}})
DBObject find = new BasicDBObject( "entity", 4);
DBObject set = new BasicDBObject( "entity.$", 10);
DBObject update = new BasicDBObject().append("$set", set);
coll.update(find, update);
Note that you can at most update only one single matching array element, even if there are other matching elements in the array. For instance, if there are two 4s in the array, only the first occurrence of 4 will get updated. This is how the positional operator works.
Whenever you use the positional operator in the update query, the find query must contain the field in the find part of the query.

Related

Return type of Linq on Datatable

I have a datatable with two columns ID & Role.
Same ID can have multiple roles.
I need to convert this table to a comma separated grouped table.
I am trying to use following query but unable to solve the issue.
LINQ:
From row As DataRow In dtData.Rows.Cast(Of DataRow)
Group row By id = row.Field(Of Integer)("ID") Into Group
Select ID, Role = String.Join(",", From i In Group Select i.Field(Of String)("Role"))
Issue
Any help will be appreciated.
Update 1:
Table structure
Needed table Structure
You could create a linq like in your comments just that this returns a list of arrays of string:
Here is the code:
(From row As DataRow In myDatatable
Group row By id = row.Field(Of String)("ID") Into Group
Select {id, String.Join(",", From i In Group Select i.Field(Of String)("Role"))}).ToList
If you need the result in a datatable you can build a new datatable
Make a for each of result and use the activity Add data row. In ArrayRow add the item and in DataTable the new data table
If you use the activity Output data table you can see the results
I am kind of confused by what you are wanting as the ultimate outcome. An idea that may guide you but not be exactly what you want is you can change a DataTable to an anonymous projection and then get what you want out of that. You can do a 'Select' off a DataTable which enters into an extension method of 'what' do you want to select. If I was to do a new {} without any class or container object after the 'new' I would be scoped to just a method or not. This is a good advantage when you want to mold something for a specific use in just a single method to use tailored to a specific view.
static void Main(string[] args)
{
DataTable d = new DataTable();
d.Columns.Add("ItemName", typeof(string));
d.Columns.Add("MinValue", typeof(float));
d.Columns.Add("MaxValue", typeof(float));
d.Rows.Add("Widget1", 0.1, 0.2);
d.Rows.Add("Widget2", 0.2, 0.4);
d.Rows.Add("Widget3", 0.1, 0.2);
var dataTable = d.AsEnumerable();
//What do you want to select? The new {} without an indicator means anonymous type projection. This will exist only in
// the scope listed.
var data = dataTable.Select(x => new { ItemName = x[0], MinValue = x[1], MaxValue = x[2] }).ToList();
//My 'data' type is now well typed for it's properties in the scope it's in.
var joined = String.Join(", ", data.Select(x => x.ItemName).ToList());
Console.WriteLine(joined);
Console.WriteLine($"{data.Count}");
Console.ReadLine();
}
EDIT 1-26-18
Strange I thought I updated the code yesterday. To get a reusable object you could bind your front end to, you just make a POCO like so:
public class Foo
{
public string Bar { get; set; }
public string MinAndMax { get; set; }
}
While you could make another DataTable, frankly DataTables are like WinForms. They get the job done, but they are archaic and not friendly to do Linq with as easily as just a well formed POCO. And if you get into using Linq it will play better with well formed objects and they are easy to create.
var data = dataTable.Select(x => new Foo { Bar = x[0].ToString(), MinAndMax = $"{x[1]} {x[2]}" }).ToList();
//My 'data' type is now well typed for 'Foo' class and it's properties in the scope it's in.
var joined = String.Join(", ", data.Select(x => $"{x.Bar} {x.MinAndMax}").ToList());

Creating a new set from components of an existing set in OPL/CPLEX

I have a set that I have read into my OPL project that looks like this:
S = {<"A","">, <"B","">, <"AB","A">, <"AB","B">, <"C","">, <"ABC","A">,<"ABC","B">, <"ABC","C">, <"ABC","AB">},
where each element <,> is a tuple with two string elements. This set represents parent-child relationships between items of interest.
From this set I need to create a new set:
S' = {<"A",{""}>, <"B",{""}>, <"C",{""}>, <"AB",{"A","B"}>, <"ABC",{"A","B","C","AB"}>},
where each element <,> is a tuple with the first element of each tuple a string and the second element of each tuple a set of strings. My attempt at creating this set is:
tuple child{
string Item;
string Child;
}
{child} Children = ...; //Reads in the set S
tuple dependents{
string Item;
{string} ItemChildren;
}
{dependents} dependentsSet = {<x.Item, y.Child> | x in Children, (y in Children : <x,y> in Children)};
Using the variable names from the above code, the purpose of creating S' is because later in my program I need to create a collection of constraints, one for each Item, and within each constraint I need to index over the ItemChildren. I'm a relative novice with OPL so I know I'm using the syntax incorrectly in the initialization of the dependentsSet variable, but I don't know how to write this statement correctly such that it creates the set I'm looking for.
Can anyone help me understand the statements required to create the set I'm after?
tuple child{
string Item;
string Child;
}
{child} Children
= {<"A","">, <"B","">, <"AB","A">, <"AB","B">, <"C","">, <"ABC","A">,
<"ABC","B">, <"ABC","C">, <"ABC","AB">};
{string} setOfParents={i.Item | i in Children};
{string} setOfChildren={i.Child | i in Children};
tuple dependents{
string Item;
{string} ItemChildren;
}
{string} kids[p in setOfParents]={k | k in setOfChildren : <p,k> in Children};
{dependents} dependentsSet = {<x, kids[x]> | x in setOfParents};
execute
{
writeln(dependentsSet);
}
gives
{<"A" {""}> <"B" {""}> <"AB" {"A" "B"}> <"C" {""}>
<"ABC" {"A" "B" "C" "AB"}>}

between (range) in mongodb query does not work

I have a db doc as follow:
Now I am trying to group by all info by time between for 2 specific time and return the sum of count
for that I wrote my code as follow:
DBCollection coll = db.getCollection("test");
DBObject groupFields = new BasicDBObject("_id", "$time");
groupFields.put("sum", new BasicDBObject("$sum", "$count"));
DBObject group = new BasicDBObject("$group", groupFields);
// filter where clause
BasicDBObject simpleQuery = new BasicDBObject();
simpleQuery.put("time", new BasicDBObject("$gt", "20140005150011"));
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
DBObject match = new BasicDBObject("$match", simpleQuery);
List<DBObject> pipeline = Arrays.asList(match, group);
AggregationOutput output = coll.aggregate(pipeline);
for (DBObject result : output.results()) {
System.out.println(result);
when I run this code it group by all elements even those time that starts with 2013...but in simpleQuery I defined a range which apparently does not work . However as soon as I remove
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011")); the code starts working. Why does it happen ? Can anyone help?
Update1 :
it seems that in the following query the second one overwrite the first one:
simpleQuery.put("time", new BasicDBObject("$gt", "20140005150011"));
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
because when I change the query it starts working
Update 2 :
when I change the code to the following it completely work:
BasicDBObject andQuery = new BasicDBObject();
simpleQuerytest.put("time", new BasicDBObject("$gt", "20130005150011"));
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
obj.add(simpleQuerytest);
obj.add(simpleQuery);
andQuery.put("$and", obj);
Now my question is what is the difference between and query and just using put ? I always thought that they are the same !!! can anyone explain?
The reference variable simpleQuery points to an instance of BasicDBObject, which is an implementation of a Map. From the java docs, when you put a key value pair into the map, it,
Associates the specified value with the specified key in this map
(optional operation). If the map previously contained a mapping for
the key, the old value is replaced by the specified value. (A map m is
said to contain a mapping for a key k if and only if m.containsKey(k)
would return true.)
The first operation:
simpleQuery.put("time", new BasicDBObject("$gt", "20140005150011"));
associates the key time to a value.
The second operation,
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
replaces the previous value of the key time. Hence only the last inserted value of time gets associated to it.
The below operation works as intended because, simpleQuerytest and simpleQuery are two different Maps, which form the input to the map containing the and operation.
BasicDBObject andQuery = new BasicDBObject();
simpleQuerytest.put("time", new BasicDBObject("$gt", "20130005150011"));
simpleQuery.put("time", new BasicDBObject("$lt", "20151105150011"));
...
andQuery.put("$and", obj);

hibernate how to assign ParameterList for the IN clause

I need to use the IN clause in the SQL sentence.
I have data in one table with the type on Int(11).
And Y have a String from another table that is the criteria.
For example, in table A i have the value 3 of type Int.
In table/process B i have the String "0123".
I need to query table A to meet this criteria:
Select * from Table A where attrib_1 IN (0,1,2,3)
Because record n have value 3, it should be returned.
So i'm trying to use .setParameterList, like this:
List<BloqueCruzamiento> bloques = session.createQuery("FROM BloqueCruzamiento AS b WHERE b.anio=:anio AND b.activo=true AND b.grupo=:categoria AND b.pr IN(:pr_set)ORDER BY b.nroParcela, b.cruza, b.pedigree")
.setParameter("anio", grupo.getAnio())
.setParameter("categoria", grupo.getCategoria())
.setParameterList("pr_set", pr_parm)
.list();
the quid is on "pr_set" parameter.
I want to know how to convert a String , "0123", to a Collection of Integers (0,1,2,3).
So I can pass this parameter to setParameterList() method.
Anapproach that I'm right now is to convert the String to a Char Array, then loop, and convert each element into an Integer Array.
Can somebody give anothe solution ?
Regards
you can use code below to get list from String
String s = "0123";
List<Integer> pr_parm = new ArrayList<Integer>();
for(int i=0;i<s.length();i++) {
if (Character.isDigit(s.charAt(i))) {
pr_parm.add(Integer.parseInt(String.valueOf(s.charAt(i))));
}
}
System.out.println(pr_parm);
Then you can use the list in your setParameterList("pr_set", pr_parm)
this was the solution.
String[] sele = grupo.getPr_sel().split(",");
Integer[] pr_parm_int = new Integer[sele.length];
for (int x=0; x<sele.length;x++){
pr_parm_int[x] = Integer.valueOf(sele[x]);
}
the first line is to parse the string and strip comas.

How do I add data to the DataTable?

How do I add data to a DataTable which has 5 Columns?
I'm using C++ (CLI).
From the MSDN
void AddRow(DataTable^ myTable){
DataRowCollection^ rc;
DataRow^ myNewRow;
// Create an array with three elements.
Object rowVals[] = gcnew Object[3];
rc = myTable->Rows;
rowVals[0] = S"hello";
rowVals[1] = S"world";
rowVals[2] = S"two";
// Add and return the new row.
myNewRow = rc->Add(rowVals);
}
You'd need to add two new values to rowVals and then you're away with it
(P.S. I changed the syntax to cli syntax by eye, it might not compile exactly as it is but should be enough to work with)