update data in Array of Structs with data in other Array of Struct - arrays

Let's say I have struct :
struct Planet {
var id : UUID
var name: String
...
}
I have an array of such structs which is constructed from data fetched from a database. I use this for a form in a browser where the user can:
edit the fields (eg change the name of Planet)
create one or more new Planets
at this time the user may not delete a Planet but it would be great if the solution would support that too
When the form is submitted I get an array with those structures (the order is also not the same as the original). What is the best/most efficient way to do update the data in the original array with the data from the second.
My current idea is:
map the original array to a dictionary with key= id, value= aPlanetStructure
loop over the second array (with the edited data) and if that 'key' can be retrieved in the dictionary (=data from first array)-> update the struct there, if not create an additional planet in the first array.
I'm not sure if this is a good approach, it seems like there could be a more efficient way (but I can't think of it). It would also not support deleting a Planet

In general, if you can separate out the elements of the array by action, you'll make your life easier.
For example:
var created= [Planet]()
var updated= [Planet]()
var deleted = [Planet]()
In your UI layer, when an edit is made, add the edited planet to the
updated array, when a planet is deleted, add it to the deleted array, etc.
Submit all 3 arrays with your form.
Loop over the results of each and pass too your create, update, and delete methods that access your database.
That will require restructuring your form code a bit, but... in general it's easier in your UI layer to tell whether someone is doing a create, an update, or a delete, than it is to mush them all together and try to figure it out after the fact by doing comparisons.

Related

Adding a new Entry in a Struct holding a TArray as Member value doesn’t update it’s entries

I am currently working on a Character Customization System where a HUDLayout dynamically create Widgets based on a set of Skins available for the Character Selected. A Skin is represented as a Struct called MaterialInstanceContainer and holds a TArray. Player can mix and match their selection according to the Body Parts they select. In order to achieve the final result, I want to create a TMap<string, MaterialInstanceContainer> so that I can map each BodyParts available for selection with the individual material instance targeting the same BodyPart.
ISSUE: My issue is as follow, when I try to foreach over my collection of Material Instances inside my Container, I do a string comparison and if the output is valid, I can then break my struct to access the Material Instance Array and ADD to it however, at the very end of the process, the length of the array inside Material Container is still at zero.
How can I add a new entry in the array that my Material Container Struct hold?
Thanks!
enter image description here
The issue here is actually pretty straight forward: in Blueprints when you 'Find' a member of Map you are not getting it by-reference, instead you get the copy.
This is exactly what happens at the end of your nested loop: You get a copy, you add item to it, and when another iteration kicks-in the copy gets terminated.
And here on my side it returns exactly the same result as expected:
The fix for that would be easy:
After editing a Copy, you can overwrite the Map member by its copy (via 'Add' node).
But in your case it will be more tricky. You cannot just plug the same BreakStruct/Array node that you just used because it would call whole Find sequence again which creates another copy. Look
If you are confused. This code actually looks like this for Unreal's point of view.
So you have to store the the Struct in local variable first, then perform any operations on it and after everything is done - overwrite the Map member by its locally stored copy. And the result is
Map member gets overwritten every time and everything is as it should be.
Well, almost... For some reason your code is stored in Macro. I think you have to change it to a Function to be able to create local struct variable. But it shouldn't be a problem in this specific case because in your code there is no logic that needs to be done in macro.
Hope, it helps

How to delete a piece of data from an array inside a Nested Collection?

I want to delete an item from an array that is inside a collection that is inside another collection (A nested collection) I have all the data that I need to achieve this, however I do not know how to write I have a slightly idea of how to (I'll be testing stuff on my own, but will leave the question here as well)
I'm using Material UI DataGrid to render my tables and to delete/edit them. I have a piece of information that is saved on my Local Storage in case I required it:
this is how my table looks:
When I select an ITEM and delete it is holding the ID of the item in the data:[Array]
those IDs are the IDs they hold in the data[array] -> :
finally I need to access this document, well I have the following
db.collection("usuarios").doc(user.uid).collection("pedidos").doc(id)
which brings the following:
which means I'm bringing the correct document, however I have no idea how to "update" or delete the array called data[], any ideas? What I want to achieve is that when I press the delete button it will update the array based on the Item selected so if it was Item ID: L-2627 then go through the array inside that collection, get the array called data and delete the item stored in the array.
Read the document into memory.
Modify the array by finding the item and removing it, again from memory.
Write the modified contents back to the document.
There is no shortcut or single operation for doing any this. The fact that the document is in a subcollection doesn't change anything. It's just how you have to modify arrays when you don't know the entire contents of the array item ahead of time.

MFC MDI CMFCPropertyGridProperty adding Array for dropdown list merging MP4 tag data

I need some guidance on how to add a drop down list from an array of data after the read info from the MP4 Tag data is parsed. The mechanism I'm using is 100% operational, this is a creature feature addition. The MP4 tag I'm working with is Genre using the ID3V1 standard. There are 191 choices. The way my app was inherited, there are 2 columns, property/value and multiple rows. All of that works. The Genre tag was setup willy nilly so you could basically type whatever and it would store it. I want to remove that and have the 191 elements in the array to choose from using the drop down list. Part of the loading process is that it will pull in whatever was in the MP4 file. So, I want the user to be able to leave as is (most likely tagged by something that supports ID3V2), or select from the populated 191 elements in the dropdown list.
The object looks like this information.h:
protected:
CMFCPropertyGridCtrl m_wndProperties;
The information.cpp looks like this:
void CInformationView::OnInitialUpdate()
{
// create property grid
VERIFY(m_wndProperties.Create(WS_CHILD|WS_VISIBLE|WS_TABSTOP| WS_BORDER, CRect(0,0,0,0), this, 0));
// get document
CMovieDoc *lpkDoc = GetDocument();
ASSERT_VALID_PTR(lpkDoc);
// add properties //Information ORDER Loading <<<<< List shortened Stack overflow question
m_wndProperties.AddProperty(lpkDoc->m_pkArtist);
m_wndProperties.AddProperty(lpkDoc->m_pkTempo);
m_wndProperties.AddProperty(lpkDoc->m_pkGenre);
CView::OnInitialUpdate();
}
The way it pulls the data in from mp4.cpp:
// Genre
m_pkGenre = new CMFCPropertyGridProperty(_T("Genre"),
COleVariant(AfxStringFromUtf8(lptTags->genre), VT_BSTR));
The pointers in mp4.h:
CMFCPropertyGridProperty *m_pkArtist;
CMFCPropertyGridProperty *m_pkTempo;
CMFCPropertyGridProperty *m_pkGenre;
Now I know that pull downs in the 2nd column (Values) can be done because other tags have simple TRUE/FALSE that can be selected, so that tells me it should be possible to create the drop down list I'm looking to do. An example of the TRUE/FALSE looks like this:
// Compilation
m_pkCompilation = new CMFCPropertyGridProperty(_T("Compilation"),
COleVariant((!VALID_PTR(lptTags->compilation)) ? (short)0 : (short)*lptTags->compilation, VT_BOOL));
I've done arrays in C for things like microcontrollers, but not entirely sure if it is the same in C++. I'm thinking it should look like this:
// Initialize Genre Array
const char *genre[4] = { "Rock", "Rap", "Soul", "House" };
The questions are:
How do I create an the array (or does my example above look correct?) to house fixed strings like "Rock", "Rap", "Soul", etc. etc?
How to modify the VALUE row to have the pull down that contains the parsed Genre tag present and then when opened, show the 191 Genre tags where one can be selected to choose from (and ultimately save which is already working).
Actual code, not references to the learn.microsoft.com, the few things I've tried crashes when I try to alter the AddProperties I assume because of the lpkDoc pointers being used.
You should not use a plain old C-style array if you do not have a strong reason to. Use a std::vector instead. You don't even need to indicate the [size].
The same goes for char *. Use a CString or astd::string instead.
const std::vector<CString> = { L"Rock", L"Rap", L"Soul", L"House" };
Don't make your life harder than it needs to be.
2.
for (size_t i= 0; i < genre.size(); i++)
{
auto gnr= genre[i];
lpkDoc->m_pkGenre->AddOption(gnr);
}
or even better
for (auto it : genre)
{
lpkDoc->m_pkGenre->AddOption(it);
}
Important note: You should not have code about properties in your doc object. You are mixing business logic with user interaction logic. Your code in the future will be a nightmare to maintain.
I do not see your lpkDoc->m_pk variable init'ed anywhere, and I bet those pointers are pointing to no man's land.

Storing the value with the Ref, as long as it's not in the datastore

I'm have a List<Ref<Entity>>. I add new entries to the list like this:
entities.add(Ref.create(new_entry));
modified.add(new_entry);
When I store the entity that contains the list, I store the list itself and all the entities that are in the modified list. This works fine.
The problem is, that I have to work with the entities-list, while I add new entries to it. This requires iterating the list multiple times. The problem here is, that the refs in the list point to old entries (which are already in the datastore) and new entries (which are not yet in the datastore).
This causes the Ref.get()-method to return null for all the yet unstored entries in the list (the ones that are still in the modified-list).
I worked around this by doing this when inserting:
Ref<T> ref = new DeadRef<>(
Key.create(data),
data
);
this.entities.add(ref);
this.modified.add(data);
This way, I can mix stored and unstored entries in one list and Ref.get() always returns a value.
This works, but I have noticed that the refs in the entities-list stay DeadRefs when I store them to the datastore and load them in again.
Will this be a problem? Is there maybe even a better way to accomplish this?
This seems like a bad idea, although I don't know what specific problems you will run into.
The "right answer" is to save your entities first.
Edit: Also look at the documentation for ofy().defer().save(), which can prevent you from issuing a lot of unnecessary save operations.

In Meteor Collections, use an array-field or another collection?

The question
In short, my question is: when an array in a document is changed, will the users receive the new array, or just the changes?
If that question is unclear, I've described my problem below.
The problem
I have a collection whose documents contain an array field two users will push values to. A document in this collection kind of looks like this:
var document = {
userId1: "...user id...", // The id of the first of the two users.
userId2: "...user id...", // The id of the second of the two users.
data: [] // The field the two users will push values to.
}
data will from the beginning be empty, and the users will then take turns pushing values to it.
When one of the user pushes some value to data, the server will send the changes to the second user. Will the second user receive the entire data-array, or just the changes (the pushed value)? I'm a little bit worried that the second user will receive the entire data-array, even though it's just a single value that's been pushed to it, and if data contains many values, I fear this will become a bottleneck.
Is this the case? If it is, using another collection for storing the values will solve it, right? Something like this:
var document = {
id: "...unique id...",
userId1: "...user id...", // The id of the first of the two users.
userId2: "...user id..." // The id of the second of the two users.
}
var documentData = {
idReference: "...the unique id in the document above...",
value: "...a value..."
}
Instead of pushing the values into an array in document, insert them into a collection containing documentData. This (I know) won't have the downside I fear the first solution has (but I rather use the first solution if it doesn't have the downside).
As per https://github.com/meteor/meteor/blob/master/packages/livedata/DDP.md
changed (server -> client):
collection: string (collection name)
id: string (document ID)
fields: optional object with EJSON values
cleared: optional array of strings (field names to delete)
Users will receive the new array. To only send "diffs," use a collection of {userId: userId, value: value} documents.
I inspected what was sent as commented by user728291, and it seems like the entire array-field is sent, and not just the pushed value. I don't know if this always is the case (I just tested with an array containing few and small values; if it contains many or big values Meteor maybe try to do some optimization I couldn't see in my tiny test), but I'll go with the solution using another collection instead of the array-field.

Resources