{thisObject : [ 0: {property1: true,property2: 4},
1: {property3: 'hello',
property4: 'goodbye'},
2: {property5: 'imagine there are 2000 of these objects and each object has 30-50 properties',
property6: 'How in the world does one remove a specific object, along with the id, for example the object corresponding to id number 1'}
]}
I cannot for the life of me figure out how to immutability remove one of the ids from the state. Any help will be appreciated.
I often recommend that data be stored in key-value objects keyed by id because those are a lot easier to work with than arrays. But in this case - removing an item matching a given id - it's actually pretty easy with arrays because array.filter() returns a new array so it's safe to use.
Assuming thisObject is a property of state and id is the id to remove:
return {
...state,
thisObject: state.thisObject.filter( obj => obj.id !== id ),
}
Related
Say my Firestore DB contains a collection of documents, each with a field that contains a large array of numbers. For Example:
{
arr: [11,13,24,16,37,50]
},
{
arr: [12,34,55,56]
},
{
arr: [12,16,27,59]
}
How can I make a query that returns all the documents where the 'arr' field contains any of the values in a certain array?
For example, if I query with [16,13] I get the first and third documents only (first one contains both 16 and 13, third one contains 16).
Please note that both the 'arr' array and the array in my query can contain a large number of values (> 1000), so I can't use 'array-contains-any'.
Is it possible to do that?
Can I structure my DB differently in order to achieve that goal?
As you know, array-contains-any support up to 10 comparison values. If you have a large array of over 1000 values, then you might be better to restructure your collection to something like this:
Example:
arr:
arr_name:
title: "arr_title"
arr_1: {
"10": true,
"11": true,
"12": true
}
Example:
db.collection("arr_name")
.whereField("arr_1.10", isEqualTo: true)
.whereField("arr_1.12", isEqualTo: true)
I have a json file looking like this:
{
"parents": [{
// array of objects
}],
"modules": {
"a": 1,
"b": 2
}
}
I want to remove they key b of the object modules.
I am running this command: jq "with_entries(.value |= del(.b))"
But this fails when the parents array is present. I get
Cannot index array with string "b"
How can I make the command ignore the parents array and only work on the modules object?
Your idea was right, but you missed the selecting the object desired inside with_entries(), hence your delete operation was attempted on all the objects in your JSON.
Since the parents record is an array type and not an object , the del function throws out an error that its not able to index the array with the given name. You need to do
with_entries( select(.key == "modules").value |= del(.b) )
The select() function filters that object keyed by name "modules" and applies the delete action on that object alone.
jq-play snippet
The objective is the get the object from Realm that contains the highest numeric value in one of its properties. The object has a persons name (a string) and a person_id (also a string).
PersonClass: Object {
#objc dynamic var name = ""
#objc dynamic var person_id = ""
}
the person_id can be a number, string or a combination. For this filter, all strings that do not contain only a number should be ignored. The table may look like this
name person_id
Henry 0000
Leroy test
Frank 3333
Steve a123
and the result should be
Henry 0000
Frank 3333 <- .last or the highest
For a simple example, let's take this array
let arrayOfWords = ["thing", "1", "stuff", "2"]
and some code to get the string "1" and "2".
let swiftResults = arrayOfWords.compactMap { Int($0) } //knowing that Int has limitations
swiftResults.forEach { print($0) } //note we can use .last to get the last one
While there is solution by getting all Realm objects and then applying a Swift filter, the problem is there could be thousands of persons and as soon as the results object is manipulated as a Swift enumerated object (like an array), it not only breaks the connection with Realm (losing the objects live updating ability) but they are are no longer lazily loaded, taking up memory and possibly overwhelming the device.
Since realm queries do not support regex, you'd have to check that no letter is contained in person_id and get the max value using #max.
let regexAnythingButDigits = "[^0-9]"
let maxNumericID = realm.objects(PersonClass.self).filter("person_id NOT CONTAINS[c] 'a' person_id NOT CONTAINS[c] 'b' AND ..[all letters in between]... AND person_id NOT CONTAINS[c] 'z' AND person_id.#max", regexAnythingButDigits)
Based on the insight provided in the answer by rs7, here's a coding solution that meets the criteria in the question.
TLDR: we build a compound AND predicate that filters Realm for all strings that have no alpha characters. i.e. get all strings that do not have 'a' AND 'b' AND 'c' etc.
This is important because there could be thousands of objects and while filtering using pure Swift is super simple code-wise, doing that goes around the lazy-loading characteristic of Realm and the entire dataset would need to be loaded into the array for filtering, which could overwhelm the device.
This solution keeps the Realm objects lazy avoiding that issue.
let charStringToOmit = "abcdefghijklmnopqrstuvwxyz" //the invalid chars
let charsOmitArray = Array(charStringToOmit) //make an array of Char objects
var predicateArray = [NSPredicate]() //the array of predicates
//iterate over the array of char objects
for char in charsOmitArray {
let c = String(char) //make each char a string
let pred = NSPredicate(format: "!(person_id CONTAINS[cd] %#)", c) //craft a predicate
predicateArray.append(pred) //append the predicate to the array
}
//craft compound AND predicate
let compound = NSCompoundPredicate(andPredicateWithSubpredicates: predicateArray)
let realm = try! Realm()
let results = realm.objects(PersonClass.self).filter(compound).sorted(byKeyPath: "person_id")
if let lastPerson = results.last {
print(lastPerson.person_id)
}
I simplified the initial dataset provided for this example and limited it to only have a-z and 0-9 characters but that could be expanded on.
I faced this issue during a migration of gremlin queries from v2 to v3.
V2-way: inE().has(some condition).outV().map().toList()[0] will return an object. This is wrapped in transform{label: it./etc/} step.
V3-way, still WIP: inE().has(some condition).outV().fold() will return an array. This is wrapped in project(...).by(...) step.
V3 works fine, I just have to unwrap an item from the array manually. I wonder if there is a more sane approach (anyway, this feels like non-graph-friendly step).
Environment: JanusGraph, TinkerPop3+. For v2: Titan graph db and TinkerPop2+.
Update: V3 query sample
inE('edge1').
has('cond1').outV(). // one vertex left
project('items', 'count'). // pagination
by(
order().
by('field1', decr).
project('vertex_itself', 'vertex2', 'vertices3').
by(identity()).
by(outE('edge2').has('type', 'type1').limit(1).inV().fold()). // now this is empty array or single-element array, can we return element itself?
by(inE('edge2').has('type', 'type2').outV().fold()).
fold()).
by(count())
Desired result shape:
[{
items: [
{vertex_itself: Object, vertex2: Object/null/empty, veroces3: Array},
{}...
],
cont: Number,
}]
Problem: vertex2 property is always an array, empty or single-element.
Expected: vertex2 to be object or null/empty.
Update 2: it turns out my query is not finished yet, it returns many object if there are no single element in has('cond1').outV() step, e.g. [{items, count}, {items, count}...]
it looks like your main issue is getting a single item from the traversal.
you can do this with next(), which will retrieve the next element in the current traversal iteration:
inE().has(some condition).outV().next()
the iteratee's structure is, i think, implementation specific. e.g. in javascript, you can access the item with the value property:
const result = await inE().has(some condition).outV().next();
const item = result.value;
I may not fully understand, but it sounds like from this:
inE().has(some condition).outV().fold()
you want to just grab the first vertex you come across. If that's right, then is there a reason to fold() at all? maybe just do:
inE().has(some condition).outV().limit(1)
I have an array of elements that I supply for a vue component as a reactive data source (I'm inspecting the data with the vue chrome extension):
the view: [A,B,C,D,E]
the data: [A,B,C,D,E]
I want to move an item (D) to a new position (before B), so first I remove the element with splice, then reinsert it at the desired index:
the view: [A,D,B,C,E]
the data: [A,B,C,D,E]
So when I hover over in the Chrome Vue inspector over the second component, in the view the third column gets highlighted. If I hover over the 3rd element in the data, in the view the 4th element get highlighted, and so on.
The view updates correctly, but I want underlying the data to follow it.
In the array the elements are objects.
I guess this is because they are passed as reference?
I think I've found it, instead of splice I should use set and remove on the vue instance:
https://v2.vuejs.org/v2/api/#Vue-set
You should avoid directly setting elements of a data-bound Array with
indices, because those changes will not be picked up by Vue.js.
Instead, use the augmented $set() method
I had the same issue as well, what happened was I didn't use unique key values for each vue object in the array. I used the index in the array as the key. So when items were resorted, some of the data would be binded to different items because keys were swapped.
What I used was a Date.now() function to initialize a UUID to set for each key
So for instance, say we had the key set to the index of the array
[ 0, 1, 2, 3, 4] - The keys
[A0,B0,C0,D0,E0] - The array of objects
[A1,B1,C1,D1,E1] - The data attribute inside each of the objects in array
So [A0] has a key of [0], and data attribute of [A1].
Say we swap [A0] and [B0]
[ 0, 1, 2, 3, 4] - the key
[B0,A0,C0,D0,E0] - the array of objects
[A1,B1,C1,D1,E1] - the data attribute assigned to each object in array
Now [A0] is binded to the data attribute of [B1], because
[B1] is binded to the key of [1] and A[0] key is [1]
This is never what you want, so you want to make each key unique instead. A common way of doing this is using a Date.now() method upon data initialization, or a create a UUID
In Summary
Example in Vue for creating a unique UUID for each object when using vue methods
methods: {
_addGroup: function() {
let result = {
sortId: this.wizardGroups.length + 1,
text: 'Hello world'
uuid: Date.now(),
};
this.wizardGroups.push(result);
}
Assign that value to the key during v-for iteration
<child-component
v-for="wizardGroup in wizardGroups"
:key="wizardGroup.uuid">
</child-component>