Compare 2arrays of dictionary on one key and merge together - arrays

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 :)

Related

How to project a specific index inside a multilevel nested array in mongodb

I have a particular field in my document which has a multilevel nested array structure. The document looks like something this
{
"_id" : ObjectId("62171b4207476091a17f595f"),
"data" : [
{
"id" : "1",
"content" : [
{
"id" : "1.1",
"content" : []
},
{
"id" : "1.2",
"content" : [
{
"id" : "1.2.1",
"content" : [
{
"id" : "1.2.1.1",
"content" : []
}
]
},
{
"id" : "1.2.2",
"content" : []
}
]
}
]
}
]
}
(The ids in my actual data is a random string, I have added a more defined id here just for readability)
In my application code the nesting level is controlled so it won't go more than 5 levels deep.
I need to project a particular object inside one of the deeply nested arrays.
I have all the information needed to traverse the nested structure. For example if I need to fetch the object with id "1.2.2" my input will look something like this:
[{id: 1, index: 0}, {id: 1.2, index: 1}, {id: 1.2.2, index: 1}]
In the above array, each element represents one level of nesting. I have the Id and the index. So in the above example, I know I first need to travel to index 0 at the top level, then inside that to index 1 , then inside that to index 1 again to find my object.
Is there a way I can only get the inner object that I want directly using a query. Or will I need to get the whole "data" field and do the traversal in my application code. I have been unable to figure out any way to construct a query that would satisfy my need.
Query
if you know the path, you can do it using a series of nested
$getField
$arrayElemAt
you can do it in one stage with nested calls, or with many new fields like i did bellow, or with mongodb variables
*i am not sure what output you need, this goes inside to get the 2 using the indexes (if this is not what you need add if you can the expected output)
Test code here
Data
[
{
"_id": ObjectId( "62171b4207476091a17f595f"),
"data": [
{
"id": "1",
"content": [
{
"id": "1.1",
"content": []
},
{
"id": "1.2",
"content": [
{
"id": "1.2.1",
"content": [
{
"id": "1.2.1.1",
"content": []
}
]
},
{
"id": "1.2.2",
"content": [1,2]
}
]
}
]
}
]
}
]
Query
aggregate(
[{"$set":
{"c1":
{"$getField":
{"field":"content", "input":{"$arrayElemAt":["$data", 0]}}}}},
{"$set":
{"c2":
{"$getField":
{"field":"content", "input":{"$arrayElemAt":["$c1", 1]}}}}},
{"$set":
{"c3":
{"$getField":
{"field":"content", "input":{"$arrayElemAt":["$c2", 1]}}}}},
{"$project":{"_id":0, "c4":{"$arrayElemAt":["$c3", 1]}}}])
Results
[{
"c4": 2
}]

In mongo db, how can I set a value in an array of arrays without knowing the index?

In Mongo DB, how can I set values in an array of arrays when the index cannot be assumed?
For example, how can I set the IdleShutdown value to "2" (instead of "10") in this blob below?
What would the command look like to correctly find the item in the list and set the value without any assumptions that the current index will stay the same? I also cannot assume any values for the second item in the list (eg, "10" could become any value)
> db.EventPluginSettingsCollection.findOne({"_id": "spot"})
{
"_id" : "spot",
"LastWriteTime" : ISODate("2019-12-16T11:04:30.499Z"),
"Name" : "Spot",
"PluginEnabled" : 1,
"DebugLogging" : false,
"Icon" : null,
"Limits" : [ ],
"DlInit" : [
[
"State",
"Disabled"
],
[
"Config",
"{}"
],
[
"IdleShutdown",
"10"
],
[
"StaggerInstances",
"50"
],
[
"PreJobTaskMode",
"Conservative"
],
[
"AWSInstanceStatus",
"Disabled"
]
],
"Meta" : {
}
}
I understand I could replace the whole blob, and I could also use individual indexes for each item, but none of these approaches are future proof should the number of items in the list change in the future.
MongoDB 3.6 introduced the filtered positional operator array update operator, $[ < identifier> ], for these types of operations. Updates using this syntax will only update elements of an array that match a specified array filter.
For example:
> db.foo.update(
... { "_id" : "spot" },
... {
... "$set" : {
... // only updates array elements matching the filter below
... "DlInit.$[element]" : [ "IdleShutdown", "2"]
... }
... },
... {
... "arrayFilters": [
... // Search for DlInit array elements that are the specified array
... { "element.0" : "IdleShutdown" }
... ]
... }
... )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.foo.find().pretty()
{
"_id" : "spot",
"LastWriteTime" : ISODate("2019-12-16T11:04:30.499Z"),
"Name" : "Spot",
"PluginEnabled" : 1,
"DebugLogging" : false,
"Icon" : null,
"Limits" : [ ],
"DlInit" : [
[
"State",
"Disabled"
],
[
"Config",
"{}"
],
[
"IdleShutdown",
"2"
],
[
"StaggerInstances",
"50"
],
[
"PreJobTaskMode",
"Conservative"
],
[
"AWSInstanceStatus",
"Disabled"
]
],
"Meta" : {
}
}

Find array in array data in MongoDB

I want find in this document groups:
"document": {
"groups": [
{
"id": "5ccd5f7f34f82b0e3315b2f6"
},
{
"id": "73b43unbfkfmdmddfdf84jjk"
}
]
}
are contains some of my query array groups ID:
[ '5ccd5f7f34f82b0e3315b2f6',
'5cdeded7ace07216f5873b5d',
'5cdee5d114edac2cc00bb333' ]
A simple find query suffices:
db.collection.find({ 'groups.id' : {$in : [ '5ccd5f7f34f82b0e3315b2f6',
'5cdeded7ace07216f5873b5d',
'5cdee5d114edac2cc00bb333' ] }})

mongodb, how to find in array other array

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.

MongoDB - Select multiple sub-dicuments from array using $elemMatch

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"}
])

Resources