Database structure: how to best design for this issue? - database

I have users that have several objects and can upload images for those objects. Each object has several items. The photos the user upload can be assigned to those items. The thing is, one object can have one specific item more than once.
To give an example: objects are cars and items are seats, windows, doors, etc. A car may have 5 seats, but all seats are the same item. The description of the image should, however, still be "seat 1", "seat 2", etc. and the user can upload multiple images for seat 2 as well.
Till now I have the following tables:
objects: id, name
items: id, name
assigned_items: id, object_id, item_id, quantity
images: id, object_id, item_id
How would you best solve this issue?
The reason I use quantity is, because if type of the item changes, then most probably of all the items. E.g. 4 seats can become 4 wheels, etc. So, if there was a row for each assigned_item, lets say seat1, seat2, seat3, etc, then this would be more difficult to change, no?

Take a look at this model:
It allows you to:
Connect multiple items to multiple objects (thanks to OBJECT_ITEM table).
Connect the same item multiple times to the same object (thanks to OBJECT_ITEM.POSITION field).
Connect multiple images to an object-item connection (thanks to OBJECT_ITEM_IMAGE table). So, we are connecting to a connection, not directly to an item.
Name the image specific to the object-item connection (thanks to OBJECT_ITEM_IMAGE.IMAGE_NAME field), instead of just specific to the image.
Ensure image name is unique per object-item connection (thanks to UNIQUE constraint "U1").
NOTE: This model can be simplified in case OBJECT:ITEM relationship is 1:N instead of the M:N, but your own attempted model seems to suggest it is M:N.
NOTE: To connect an image directly to OBJECT (instead of OBJECT_ITEM), you'd need additional link table (OBJECT_IMAGE) in "between" OBJECT and IMAGE.
Example data:
OBJECT:
Car
ITEM:
Seat
OBJECT_ITEM:
Car-Seat-1
Car-Seat-2
Car-Seat-3
Car-Seat-4
Car-Seat-5
OBJECT_ITEM_IMAGE:
Car-Seat-1-Image1 "Seat1 Image"
Car-Seat-2-Image1 "Seat2 Image"
Car-Seat-2-Image2 "Seat2 Alternate Image"
Car-Seat-3-Image1 "Seat3 Image"
Car-Seat-4-Image1 "Seat4 Image"
Car-Seat-5-Image1 "Seat5 Image"
IMAGE:
Image1
Image2

Unless you actually mean that items can belong to multiple objects, using assigned_items is not helpful. If I understand you correctly, your main concern is that you sometimes have images that are for part of an item, so how do you describe the image?
Here is what I suggest:
OBJECT: id, name
ITEM: id, name, quantity, object_id
IMAGE: id, name (null), object_id (null), item_id (null)
If your DBMS supports constraints, have a constraint on IMAGE to enforce one or the other of object_id or item_id (but not both). This allows you to define the image as being either for an item or for the object as a whole.
When you query for the name of an image, you would use the COALESCE function (or your DB's equivalent) to pick up the image override name (if it exists) or the object/item name (if the override doesn't exist).

Related

How can i upsert to multiple external Id's in Salesforce?

I have an Account object in Salesforce and I have an custom field called ExternalText. I have marked the field as and External Id and
"Set this field as the unique record identifier from an external system"
There are 2 accounts that have this field set to a value of E1 in Salesforce.
I want to do an upsert from a csv file using DataLoader and the csv looks something like this:
External Description
E1 Description 1
E1 Description 2
But when i do the upsert i get the error:
ExternalTest: more than one record found for external id field: [<id1>, <id2>]
I would have expected the Description field for both to be updated to Description 1 and then Description 2, so if i view the object in Salesforce the Description field would say Description 2
How can i do this ?
You can't do it like that. Upsert has to find 0 or exactly 1 record with that external id. On 0 it'll try to create, on 1 it'll try to update, anything else - error.
For most normal usages you'll want fields marked as ext id to also be marked unique. If this isn't unique at source - you need different value in your field or bite the bullet, learn SF record IDs and do plain old query + update for example.
There's 1 edge case why ext id doesn't automatically mark field unique but if you rely on that technicality I'd say you have bigger problems. Imagine system where both UK and Germany created customer ID 123 and they want to push it to Salesforce. They both claim they were first and absolutely won't change their unique ID. So the trick is you can pull it off with right sharing rules. Upsert done with user that only sees UK data will work and update only UK customer. As I said - it's a technicality, in a "you think you're clever but you just made admin's job trickier" area.

Query of Arrays in Salesforce

I need to do 1 of two things (I believe):
1- Get a Custom Object ID so I can query it directly
2- Get a list of values of a specific field within the Object entries.
Ultimate End goal:
Add and modify rows in my custom object via external API. However to do this I need to check and make sure my new entry/row does not already exist.
What I have:
I have a custom object (called Customer_Arrays__c). It is a table that I can add new rows to (I will call entrys). Each entry has 6 or 7 fields. 1 of these fields is called (external_ID__c). This is the field I utilize to match to new incoming data to see if the entry already exists, or if it needs to add a new row to my table. This Customer_Arrays__c is a child to my opportunity I believe – it is part of every opportunity and each line item I add has a field defaulted to the opportunity.
Help I need:
1- How do I query the value of my Cutomer_Arrays__c based upon an opportunity ID?
2- How do I query a list of values in my (external_ID__c) based upon an opportunity ID?
Thanks for your help! I have read half a dozen+ posts on similar topics and am missing something. Examples of some Past try's that failed:
Select external_ID__c,FROM Custom_Arrays__c WHERE Opportunity='00...'
Select Id (Select ID, Custom_Arrays__c from Custom_Arrays__c) from Opportunity where id ='00...'
List FROM Custom_Arrays__c WHERE Opportunity='00...'
Select Id, external_ID__c, (Select external_ID__c FROM Custom_Arrays__c) WHERE Opportunity__c='00...'
Thanks again!
Only you know how did you name the lookup field (foreign key) from arrays to Opportunity. You'll need to check in setup, next to where external_ID__c is. Since it's a custom field (gets __c at the end), my guess is you went with default.
Try
SELECT Id, Name, External_Id__c
FROM Customer_Arrays__c
WHERE Opportunity__c = '006...'
Thank you eyescream, that got me almost all the way there. Turns out I also needed a __r for the parent child relationship.
Here is a snip out of my final code that works - I think it covers everything:
SELECT Field1__c, Opportunity__r.Id, Opportunity__r.Opportunity__c,
FROM Customer_Arrays__c
WHERE Opportunity__r.Id = '006...'.
Thank you so very much!!!

Is it possible to nest values based on key column in AppSheet?

I have a table connected to AppSheet that has a column called "Names" there are many values that have the same name with different information. Is there anyway in AppSheet to have the user tap on one name and have all of the values show up that have the same Customer name. Essentially grouping.
I know there is a community on Google Plus for AppSheet but it doesn't seem very active my question has been sitting on the site for weeks. If anyone needs more clarification please ask.
Not very clear what you are trying to achieve, but you can correct me if I'm wrong.
You want in the Inline view of any given Customer, to have a list of referenced values.
You can do this with a SELECT() function. In Data > Columns > + "Virtual column"
In the "App formula" input add your function.
For example: SELECT( myTable[myColumn], [Name] = [_THISROW].[Name])
What this does:
List all values from column named "myColumn" in table "myTable"
where "Name" has the same "Name" as this row,
https://help.appsheet.com/expressions/functions/select
If you want to list not only values but a list of referenced rows from another table, you should use REF_ROWS.
For example REF_ROWS("myOrdersTable", "orderCustomer")
What this does: list all rows from table named "myOrdersTable" where column named "orderCustomer" has the same value as the unique KEY of this row.
REF_ROW virtual columns are generated automatically when you give a "REF" type to any column. In this example if you go to Data > Columns > "myOrdersTable" and change the type of "orderCustomer" to "REF" with "ReferencedTableName" to "myCustumerTable", a virtual column with list of referenced rows will be generated in "myCustumerTable" table after you save.
https://help.appsheet.com/data/references/references-between-tables

"2d Search" in Solr or how to get the best item of the multivalued field 'items'?

The title is a bit awkward but I couldn't found a better one. My problem is as follows:
I have several users stored as documents and I am storing several key-value-pairs or items (which have an id) for each document. Now, if I apply highlighting with hl.snippets=5 I can get the first 5 items. But every user could have several hundreds items, so
you will not get the most relevant 5 items. You will get the first 5 items ...
Another problem is that
the highlighted text won't contain the id and so retrieving additional information of the highlighted item text is ugly.
Example where items are emails:
user1 has item1 { text:"developers developers developers", id:1, title:"ms" }
item2 { text:"c# development", id:2, title:"nice!" }
...
item77 ...
user2 has item1 { text:"nice restaurant", id:3, title:"bla"}
item2 { text:"best cafe", id:4, title:"blup"}
...
item223 ...
Now if I use highlighting for the text field and query against "restaurant" I get user2 and the text nice <b>restaurant</b>. But how can I determine the id of the highlighted text to display e.g. the title of this item? And what happens if more relevant items are listed at the end of the item-list? Highlighting won't display those ...
So how can I find the best items of a documents with multiple such items?
I added my two findings as answers, but as I will point out each of them has its own drawbacks.
Could anyone point me to a better solution?
One of my rules of thumb for designing Solr schemas is: the document is what you will search for.
If you want to search for 'items', then these 'items' are your documents. How you store other stuff, like 'users', is secondary. So 'users' could be in another index like you mentioned, they could be "denormalized" (e.g. their information duplicated in each document), in a relational database, etc. depending on RDBMS availability, how many 'users' there are, how many fields these 'users' have, etc.
EDIT: now you explain that the 'items' are emails, and a possible search is 'restaurant X' and you want to find the best 'items' (emails). Therefore, the document is the email. The schema could be as simple as this: (id, title, text, user).
You could enable highlighting to get snippets of the 'text' or 'title' fields matching the 'restaurant X' query.
If you want to give the end-user information about the users that wrote about 'restaurant X', you could facet the 'user' field. Then the end-user would see that John wrote 10 emails about 'restaurant X' and Robert wrote 6. The end-user thinks "This John dude must know a lot about this restaurant" so he drills down into a search by 'restaurant x' with a filter query user:John
You could use use two indices: users->items as described in the question and an index with 'pure items' referencing back to the user.
Then you will need 2 queries (thats the reason I called the question '2d Search in Solr'):
query the user index => list of e.g. 10 users
query the items index for each user of the 1. step => best items
Assume the following example:
userA emails are "restaurant X is bad but restaurant X is cheap", "different topic", "different topicB" and
userB emails are "restaurant X is not nice", "revisited restaurant X and it was ok now", "again in restaurant X and I think it is the best".
Now I query the user index for "restaurant X" and the first user will be userB, which is what I want. If I would query only the item-index I would get the item1 of less relevant userA.
Drawbacks:
bad performance, because you will need one query against the user index and e.g. 10 more to get the most relevant items for each user.
maintaining two indices.
Update to avoid many queries I will try the following: using the user index to get some highlighted snippets and then offering a 'get relevant items'-button for every user which then triggers a query against the item index.
You can use the collapse patch and store each item as separate document linking back to the user.
The problem of that approach is that you won't get the most relevant user. Ie. the most relevant item is not necessarily from the most relevant user (because he can have several slightly less relevant items)
See the "Assume the following example:" part in my second answer.

How to best represent items with variable # of attributes in a database?

Lets say you want to create a listing of widgets
The Widget Manufacturers all create widgets with different number and types of attributes. And the Widget sellers all have different preferences on what type and number of attributes they want to store in the database and display.
The problem here now is that each time you add in a new widget, it may have attributes on it that donot currently exist for any other widget, and currently you accomplish this by modifying the table and adding in a new column for that attribute and then modifying all forms and reports to reflect this change.
How do you go about creating a database which takes into account that attributes on a widget are fluid and can change from widget to widget.
Ideally the widget attributes should be something the user can define according to his/her preference and needs
I would have a table for widgets and one for widget attributes. For example:
Widgets
- Id
- Name
WidgetAttributes
- Id
- Name
Then, you would have another table which has what widgets have which attributes:
WidgetAttributeMap
- Id
- WidgetId
(a value from the Id column in the Widget table)
- WidgetAttributeId
(a value from the Id column in the WidgetAttribute table)
This way, you can add attributes to widgets by modifying rows in the WidgetAttributeMap table, not by modifying the structure of your widget table.
casperOne is showing the way, although I would personally add yet one more table for the attribute values, ending up with
Widgets
-WidgetID (pk)
-Name
WidgetAttributes
-AttributeID (pk)
-Name
WidgetHasAttribute
-WidgetID (pk)
-AttributeID (pk)
WidgetAttributeValues
-ValueID (pk)
-WidgetID
-AttributeID
-Value
In order to retrieve the results, you want to join the tables and perform an aggregate concatenation, so you can end up with data looking like (for example):
Name Properties
Widget1 Attr1:Value1;Attr2:Value2;...etc
Then you could split the Properties string in your Business Logic Layer and use as you wish.
A suggestion on how to join the data:
SELECT w.Name, wa.Name + ':' + wav.Value
FROM ((
Widgets w
INNER JOIN
WidgetHasAttribute wha
ON w.WidgetID = wha.WidgetID)
INNER JOIN WidgetAttributes wa
ON wha.AttributeID = wa.AttributeID)
INNER JOIN WidgetAttributeValues wav
ON (w.WidgetID = wav.WidgetID AND wa.AttributeID = wav.AttributeID)
You can read more on aggregate concatenation here.
As far as performance is concerned, it shouldn't be a problem as long as you make sure to index all columns that will be frequently read - that is
All the ID columns, as they will be compared in the join clauses
WidgetAttributes.Name and WidgetAttributeValues.Value, as they will be concatenated

Resources