I'm working with mongodb and I'm dealing with aggregate to join two collections, now I would like to convert my result
"Users" : [
[
"Carl",
"John",
"Ever"
],
[
"Dani",
"GG",
"Sussan"
],
.... N arrays
]
to this output
"Users" : [
"Carl",
"John",
"Ever",
"Dani",
"GG",
"Sussan",
..... M elements from N arrays
]
Query
reduce starting from []
concat each array member to one flatten array
Test code here
aggregate(
[{"$set":
{"Users":
{"$reduce":
{"input":"$Users",
"initialValue":[],
"in":{"$concatArrays":["$$value", "$$this"]}}}}}])
Related
I have a small mongo collection with inner arrays of strings.
{
"_id" : ObjectId("62853dc84409dcc9213f8bca"),
"test" : [
"aaaa",
"bbb",
"ccc"
]
}
{
"_id" : ObjectId("62853dd74409dcc9213f8bcb"),
"test" : [
"aaa",
"bbbb",
"ddddd"
]
}
How I can modify inner values in array with string length criteria, using current value?
For example i want to concat * to all elems with length 3.
Result must be.
{
"_id" : ObjectId("62853dc84409dcc9213f8bca"),
"test" : [
"aaaa",
"bbb*",
"ccc*"
]
}
{
"_id" : ObjectId("62853dd74409dcc9213f8bcb"),
"test" : [
"aaa*",
"bbbb",
"ddddd"
]
}
I have some code, but it gives no result.
db.studs.updateMany(
{},
{ $set: {"test.$[element]": { "$concat": ["element", " ", "*"]}}},
{ arrayFilters: [{"element": {"$strLenCP": {"$eq": 3}}}]})
Query
you need $concat which is a aggregate operator
you can do it with pipeline update MongoDB >= 4.2
map and check size, if size=3 concat "*", else dont change the member of the array
*you tried to do it with update operators, but we cant mix the aggregate and the update operators, we either do pipeline update or normal update
Playmongo
db.studs.update({},
[{"$set":
{"test":
{"$map":
{"input": "$test",
"in":
{"$cond":
[{"$eq": [{"$strLenCP": "$$this"}, 3]},
{"$concat": ["$$this", "*"]}, "$$this"]}}}}}],
{"multi": true})
I have two arrays. In first all categories and in second there are selected categories. I want to match those objects and then :
- Either I want to merge selected array into main array
- Or I want new array mapped with selected data.
Here is my arrays :
self.arrAllCategories = [
[
"_id": “1”,
"category_name": "Table”,
"is_selected" : false
],
[
"_id": “2”,
"category_name": “Chair”,
"is_selected" : false
],
[
"_id": “3”,
"category_name": “Fan”,
"is_selected" : false
],
[
"_id": “4”,
"category_name": “WallFrame”,
"is_selected" : false
]
]
And so on….
And selected categories array :
self.arrSelectedCats = [
[
"_id": “1”,
"category_name": "Table”,
"is_selected" : true
],
[
"_id": “3”,
"category_name": “Fan”,
"is_selected" : true
],
]
I have to display categories screen with selected categories in different style and non selected categories in just gray look. So How I can merge and get one array to load data in collection view ?
let yourKey = "_id"
var nonSelected = arrAllCategories.filter{ !(arrSelectedCats.map { $0[yourKey] as? String }).contains(($0[yourKey] as? String)) }
print(nonSelected)
Try this :)
I need some help. I am trying to find an array in another array.
Records:
{
"_id" : ObjectId("56b7e6966213e8d142ef55b7"),
"users" : [
ObjectId("56b0e547a838b5a45b4d0100"), // 0
ObjectId("56a7e16e37e5adf32b97cc3d") // 1
]
},
{
"_id" : ObjectId("56b7e6966213e8d142ef55b7"),
"users" : [
ObjectId("56b0e547a838b5a45b4d0100"),
ObjectId("56a7e16e37e5adf32b97cc3d"),
ObjectId("56b7e6b96213e8d142ef55b8")
]
}
I'm trying to find only first record "_id" : ObjectId("56b7e6966213e8d142ef55b7"),
I'm using query:
db.collection.find({"users" : { $in: [
ObjectId("56b0e547a838b5a45b4d0100"),
ObjectId("56a7e16e37e5adf32b97cc3d")
]}})
or
db.collection.find({ $and: [{
"users": ObjectId("56b0e547a838b5a45b4d0100")
}, {
"users": ObjectId("56a7e16e37e5adf32b97cc3d")
}]})
Response gives me two records.
This request gives me the correct response:
db.collection.find({"users" : [
ObjectId("56b0e547a838b5a45b4d0100"), // 0
ObjectId("56a7e16e37e5adf32b97cc3d") // 1
]})
but if record has an array like this:
{
"_id" : ObjectId("56b7e6966213e8d142ef55b7"),
"users" : [
ObjectId("56a7e16e37e5adf32b97cc3d"), // 1
ObjectId("56b0e547a838b5a45b4d0100") // 0
]
}
it doesn't work
$all, $eq, $in also doesn't work
db.rooms.find({
users: {
$all: [
ObjectId("56a7e16e37e5adf32b97cc3d"),
ObjectId("56b0e547a838b5a45b4d0100")
]
}
})
I need to find rows where [1,2] == [1,2] or [1,2] == [2,1]
not where [1,2,3] == [1,2]
I will appreciate if somebody can help me.
If all you expect is the resulting document with "only" those two array entries, then the combination of conditions you want is $all and $size:
db.rooms.find({
"users": {
"$all": [
ObjectId("56b0e547a838b5a45b4d0100"),
ObjectId("56a7e16e37e5adf32b97cc3d")
],
"$size": 2
}
})
Where $all is basically an $and with shorter syntax, and the $size retricts that since the list as n entries, then you only want to match something of that particular length/size.
This is better than specifying the array directly, since it will match in either order, as opposed to this statement that would not match considering the order is different and therefore not an "exact" match:
db.rooms.find({
"users": [
ObjectId("56a7e16e37e5adf32b97cc3d"),
ObjectId("56b0e547a838b5a45b4d0100")
]
})
So logically the array contains "all" the specified entries, and is the same "size" as the input and no different.
I want to iterate over a nested array I created in Freemarker but can't figure out how to print each value.
The array var
<#assign filters = [
{ "p1" : [ "performance" ] },
{ "p2" : [ "nav" ] },
{ "p3" : [ "quarterly" ] },
{ "f1" : [ "50496", "50497", "50501" ]},
{ "f2" : [ "51202", "51196", "51203", "51246", "51207", "51260" ]},
{ "f3" : [ "50504", "50505", "50506" ]},
{ "f4" : [ "50507", "50508", "50509", "50510", "50512" ]}
]>
Iterating over the array
<#list filters as filter>
${filter}'<#sep>,
</#list>
I want to create an output that looks like this:
$.plugin.function({
p1: 'performance',
p2: 'nav',
p3: 'quarterly',
fi: '50496' + '|' + '50497' + '|' + '50501',
f2: etc....
});
My error is this:
For "${...}" content: Expected a string or something automatically
convertible to string (number, date or boolean),
but this has evaluated to an extended_hash
Any suggestions?
The issue is that Freemarker doesn't have a way to convert filter (a hash) into a string. I think that you want the keys function. Where you now have
${filter}'<#sep>,
You'd instead call
<#list filter?keys as prop>
...
</#list>
and iterate over those keys. In your example there would only be one key per filter and the value
filter[prop]
would be the array, that you'd also have to iterate over.
See Freemarker iterating over hashmap keys
I think you overcomplicate the data structure by using a list of hash-es. Instead, just use a hash:
<#assign filters = {
"p1" : [ "performance" ],
"p2" : [ "nav" ],
"p3" : [ "quarterly" ],
"f1" : [ "50496", "50497", "50501" ],
"f2" : [ "51202", "51196", "51203", "51246", "51207", "51260" ],
"f3" : [ "50504", "50505", "50506" ],
"f4" : [ "50507", "50508", "50509", "50510", "50512" ]
}>
<#list filters?keys as name>
${name}: <#list filters[name] as value>'${value}'<#sep> + '|' + </#list><#sep>,
</#list>
(Another possibility would be a list of lists, but that's less natural.)
I have a collection like the following:-
{
_id: 5,
"org_name": "abc",
"items": [
{
"item_id": "10",
"data": [
// Values goes here
]
},
{
"item_id": "11",
"data": [
// Values goes here
]
}
]
},
// Another sub document
{
_id: 6,
"org_name": "sony",
"items": [
{
"item_id": "10",
"data": [
// Values goes here
]
},
{
"item_id": "11",
"data": [
// Values goes here
]
}
]
}
Each sub document corresponds to individual organizations and each organization has an array of items in them.
What I need is to get the select individual elements from the items array, by providing item_id.
I already tried this:-
db.organizations.find({"_id": 5}, {items: {$elemMatch: {"item_id": {$in: ["10", "11"]}}}})
But it is returning either the item list with *item_id* "10" OR the item list with *item_id* "11".
What I need is is the get values for both item_id 10 and 11 for the organization "abc". Please help.
update2:
db.organizations.aggregate([
// you can remove this to return all your data
{$match:{_id:5}},
// unwind array of items
{$unwind:"$items"},
// filter out all items not in 10, 11
{$match:{"items.item_id":{"$in":["10", "11"]}}},
// aggregate again into array
{$group:{_id:"$_id", "items":{$push:"$items"}}}
])
update:
db.organizations.find({
"_id": 5,
items: {$elemMatch: {"item_id": {$in: ["10", "11"]}}}
})
old Looks like you need aggregation framework, particularly $unwind operator:
db.organizations.aggregate([
{$match:{_id:5}}, // you can remove this to return all your data
{$unwind:"$items"}
])