Scala MongoDB Casbah need to build a dynamic $or query - casbah

Using Scala, MongoDB, Casbah.
Given a random list of strings:
val names = {
val listBuffer = new ListBuffer[String]
for(n <- 1 to (new Random().nextInt(5) + 1)){
val name = ((new Random().nextInt(26) + 65).asInstanceOf[Char]).toString
listBuffer += name
}
listBuffer.toList
}
Given a MongoDB document structure:
"_id": <uuid>
"name": <string>
How do I find all documents that have a name equal to an entry in my list using a single single MongoDBCollection.find() statement? (i.e using $or)
Thanks,
- Don

MongoDB has conditional operator $in that lets test if a field's value is in a list of values (documentation)
collection.find({name: {$in: ["aaa", "bbb", "ccc"]}})
In Casbah this will look like
collection.find("name" $in names)

Related

Get a filtered list from a terraform map of objects?

I have a list of users with characteristics like this and I want to create a local variable that includes the names of the users in the "maker" group.
variable "users" {
type = map(object({
groups = list(string)
}))
default = {
"kevin.mccallister" = {
groups = ["kids", "maker"],
},
"biff" = {
groups = ["kids", "teens", "bully"],
},
}
}
I want to write the local like this, but it complains
Error: Invalid 'for' expression ... Key expression is required when
building an object.
locals {
makers_list = flatten({
for user, attr in var.users: user
if contains(attr.groups, "makers")
})
}
How can I take that map of objects and get out a list of names based on group affiliation?
flatten() is not required for this. Also, the {} is pushing this to build an object. You can instead build a list using [] and then it will create a list of the users filtered by their group association.
makers_list = [
for user, attr in var.users: user
if contains(attr.groups, "makers")
]

How to add any symbols after prefix_?

is there any solution? e.g. I have data in Map with key favorites_ prefix and values _suffix (for example: favorites_jeans, favorites_suit,...,). I want to by dint of loop get that values and set in List, because of it I must give keys of map, right?
I want to know how can I get values of myMap["favorites_*"] (* - after the favorites_ any symbols).
List<String> favoritesStrings = ['favorite_name','favorite_jeans',];
Map<String,dynamic> myMap = {
favoritesStrings[0]:'0',
favoritesStrings[1]:'1',
'someKey':'2',
'anotherKey':'3',
};
favoritesStrings.forEach((favorite)=>print(myMap[favorite]));//prints 0 1
As per what I understood, you want to fetch value from map using "favorites_" + a dynamic value from list as key.
You just have to use String templates and use $ to insert suffix variable to build key dynamically:
List<String> suffixList = ["jeans", "suit", "shirt"];
for(String suffix in suffixList) {
var item = myMap["favorites_$suffix"];
// Do something with item
}
Hope it helps

Java 8 Streams API to filter Map entries

I have a the following container in Java that I need to work on
Map<String, List<Entry<Parameter, String>>>
Where Parameter is an enumerated type defined as follows:
public enum Parameter {
Param1,
Param2,
Param3
}
The code below shows how I initialize the map structure - effectively putting 2 rows in the container.
Map<String, List<Entry<Parameter, String>>> map2 = new HashMap<String, List<Entry<Parameter, String>>>() {{
put("SERVICE1", new ArrayList<Entry<Parameter, String>>(){{
add (new AbstractMap.SimpleEntry<>(Parameter.Param1,"val1"));
add (new AbstractMap.SimpleEntry<>(Parameter.Param2,"val2"));
add (new AbstractMap.SimpleEntry<>(Parameter.Param3,"val3"));
}});
put("SERVICE2", new ArrayList<Entry<Parameter, String>>(){{
add (new AbstractMap.SimpleEntry<>(Parameter.Param1,"val4"));
add (new AbstractMap.SimpleEntry<>(Parameter.Param2,"val5"));
add (new AbstractMap.SimpleEntry<>(Parameter.Param3,"val6"));
}});
}};
I need to use the java 8 streams api to find the val1 and val2 values from "SERVICE1" but I do not know the correct java streams filter and mapping syntax.
The nearest thing I can come up with is the following, but this only filters at the top level and it returns a list of lists rather than the list of Parameter.Param1,"val1" & Parameter.Param2,"val3" that I am looking for from the SERVICE1 row.
List<List<Entry<Parameter, String>>> listOfLists = myMap.entrySet().stream()
.filter(next -> next.getKey().equals("SERVICE1"))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
listOfLists.size();
If you only need the "val1" and "val2" values, you can first use getOrDefault to get the corresponding list, and then filter on the entries' keys to get entries with Param1 or Param2 as key, and finally apply map again to get the values of these entries.
List<String> list =
myMap.getOrDefault("SERVICE1", Collections.emptyList())
.stream()
.filter(e -> e.getKey() == Parameter.Param1 || e.getKey() == Parameter.Param2)
.map(Map.Entry::getValue)
.collect(Collectors.toList());
Also you might be interested to look at Efficiency of Java "Double Brace Initialization"?

Meteor.find multiple values in an array

I am using auto schema to define an array field. I need to find documents where multiple specific values are contained in that array. I know I can use the $in: operator while $in: can only match either one of the value in the first array against the second array while I would need to match any record that have all value in the first array. How I can achieve this?
Schema Definition
Demands = new Mongo.Collection("demands");
var demandschema = new SimpleSchema({
ability: {type:array},
language: {type: array}});
Demands.attachSchema(demandschema);
Contents Definition
DemandsSet=[
{ability: ["laser eye", "rocky skin", "fly"], language: ["english", "latin", "hindu"]},
{ability: ["sky-high jump", "rocky skin", "fly"], language: ["english", "latin", "japanese"]},
{ability: ["rocky skin", "sky-high jump"], language: ["english", "latin", "russian"]}
];
Target Set
var TargetAbility = ["rocky skin", "fly"];
var TargetLanguage = ["english", "hindu"];
When I do a $in operation
Demands.find({ $and: [
{ ability: { $in: TargetAbility }},
{ language: { $in: TargetLanguage }}
]}).fetch();
I will return me with all records, while it is not correct, how can I perform such a find operation?
$in: is not going to work for you because it looks for any match when comparing two arrays, not that all elements of one array must be present in the other.
You can write complete javascript functions to execute the required comparisons inside the mongodb query. See $where:
For example:
Demands.find({$where:
"this.ability.indexOf(TargetAbility[0]) > -1 &&
this.ability.indexOf(TargetAbility[1]) > -1 &&
this.language.indexOf(TargetLanguage[0]) > -1 &&
this.language.indexOf(TargetLanguage[1]) > -1" });
If your candidates have other than 2 entries each then you can write a more general form of this of course.
Note that Meteor apparently does not support the function() form of $where: but that restriction may be dated.
Also note that $where: cannot take advantage of indexes so performance may not be suitable for large collections.

How use a variable name to point different data types with the same name?

I have 2 List one stores the name of filterable columns(of type DropDown) and another store the values to load in those filterable columns.
List<string> filterableFields = new List<string>() { "A_B", "C_D", "E_F" };
List<string> AB, CD , EF;
Now at the run time I get the data from web service and I have written a function to to extract values for these filterable fields and store the values to 2nd List.
private void prepareListForFilterableColumns(XDocument records)
{
foreach (var currentField in filterableFields)
{
var values = (from xml in records.Descendants(z + "row")
let val = (string)xml.Attribute("ows_" + currentField.Replace("_", "_x0020_"))
where val != ""
orderby val
select val
).Distinct();
switch (currentField)
{
case "A_B": AB = values.ToList(); break;
case "C_D": CD = values.ToList(); break;
}
}
}
Now I was thinking that instead of hard coding the assignment in swtich case block, If I could just use the first List name "A_B" and replace "_" from it to point to my 2nd List and assign values.ToList() to it.
I understand that c# is a static language, So not sure if we can achieve this, but IF I can it will make my function generic.
Thanks a lot in advance for time and help.
Vishal
You could use a dictionary of lists of strings instead of 3 lists to store the values.
Dictionary<string, List<string>> val lists = new Dictionary<string,List<string>>();
And make the keys of the dictionary equal to the filterables: "AB", "CD",..
then, instead of AB you would use valLists["AB"] and could then reference reach list based on a string key.
The other option would be to use reflection but that would be slower and unnecessarily a bit more complicated.

Resources