Disambiguation - is it possible?


#1

Is it possible to retrieve disambiguating data with Select2?
For example, if there are two "John Smith"s:
Smith John
---- Star of stage and screen
Smith John
---- Recording artist

TIA


#2

Do you mean “retrieve” from an external data source (e.g., AJAX)? If so, the answer is yes, as long as each data item has a unique id attribute (see the Select2 data format documentation).

However, if by “retrieve” you mean “match”, then the answer is still yes. Even if you initialize the Select2 with hard-coded HTML, Select2 will provide a unique id value for each <option> element. Ideally, you would do that yourself by providing unique value attributes for each <option>, even if multiple options have the same display text.


#3

Thank you John, this looks promising. I’ll flesh out a more detailed example of what I need.
Let’s say my db has a names table and a details table. The names have unique ids, and those same ids are used in the details table.
So “Smith John” has an id of 37, and his details are “id:37, detail:Star of stage and screen”.
Another “Smith John” has an id of 48, and his details are “id:48, detail:Recording artist”.
FWIW, I don’t actually store names that way!
What I need is to look up the name, but also retrieve the detail and display a neatly formatted list. My previous post shows a very simple example.
I appreciate your help. If there is sample code anywhere it would be a boon.
TIA


#4

I assume you’re using Select2’s AJAX feature to retrieve the data (filtered based on the user’s input). So, if I understand your requirement correctly, if the user starts typing “john”, you want Select2 to retrieve both “John Smith” entries (IDs 37 and 48 in your example).

To use the AJAX feature, you must have a server-side URL that receives the request from Select2, queries the database based on the user’s search term, and returns any matching results. Without knowing for sure what your DB technology is, I’m going to assume from your example that it’s a no-SQL DB (e.g., MongoDB, CouchDB, etc.) No-SQL databases don’t typically do table joins natively, so your server-side logic will have to take the request from Select2 (which includes the user’s search term), query your names table for all records that match the user’s search term, and then for each of those matching name records, query the details table (by the name record’s ID) to get the details for that name, and then return a single record with the combined data.

So if your artist search URL is https://your-app.server.com/search/artists, then Select2’s request will look like: https://your-app.server.com/search/artists?term=john&q=john&_type=query.

In JavaScript (e.g., node.js) your server-side code to handle this request might look something like this:

const MongoClient = require("mongodb").MongoClient;
const dbUrl = "mongodb://your-db.server.com:27017/";

searchArtists = function(request, response) {
	const searchTerm = request.query.term; // "john"
	const nameQuery = new RegExp("^" + searchTerm, "i"); // matches only at the start of the name, case-insensitive.
	const results = [];
	MongoClient.connect(dbUrl, function(err, db) {
		if (err) throw err;
		const dbo = db.db("your-db");
		// Get matching name records:
		dbo.collection("names")
			.find({ name: nameQuery })
			.toArray(function(err, matchingNameRecs) {
				if (err) throw err;
				// Get the details for each matched name record, and "join" it
				// with the name record into a single record in the Select2
				// data format:
				matchingNameRecs.forEach((rec) => {
					dbo.collection("details").findOne({id: rec._id}, 
						function(err, detRec) => { 
							if (err) throw err;
							// Add the "joined" record to the results array.
							results.push({
								"id": rec._id,
								"text": rec._name,
								"detail": detRec.detail
							});
						});
				}); // end of forEach().
			});
		db.close();
	});
	
	// At this point the `results` array contains all the matching, "joined" records.
	// Moreover, the records are in Select2's required data item format.
	// So we send the results in the response format Select2 expects.
	response
		.addHeader('Content-Type', 'application/json')
		.setStatus(200)
		.send({"results": results});
};

Your code will differ somewhat in how you connect to and query your database, and how you send the HTTP response, but I hope you get the general idea.

Given the logic above, the search for “john”, the response from the server will look like:

{
    results: [
        { "id": 37,
          "text": "John Smith",
          "detail": "Star of stage and screen"
        },
        { "id": 48,
          "text": "John Smith",
          "detail": "Recording artist"
        }
     ]
}

It’s up to you how you want to display this data in the Select2. You can use custom templateResult and templateSelection functions to include both the name (“text” property) and detail text in the dropdown and the selection box. (You can use the same function for both if you want the same display.)

I hope this helps.


#5

Wow! That’s a remerkably detailed response. Thank you very much.
I owe you. Is there anywhere I can donate something for you?


#6

That’s a very kind offer, but not necessary. I enjoy giving back to the community. Your thanks (and a “like” on my response) is more than enough.

Good luck with your project!


#7

Okay. Thanks again, I really appreciate it…