How do you display "recommended items" that have the most Selected Tags in common?

Hi everyone!

I’m trying to figure out how to create a “related items” section displaying items with the same “Selected Tags" as the current dynamic page item.

My website showcases local films and their credits on a dynamic page. I would like to add a “recommended films” section at the bottom of the dynamic page that shows films with similar moods and genres.

In my collection, I have:
—> moods (as selected tags)
—> genres (as selected tags)
—> film runtime (as number)

I would like the "recommended films” repeater to first show the films that:
—> have the most amount of similar moods
—> have the most amount of similar genres
—> are < 4 min

Here is the code I have so far:

//-------------Imports-------------//

import wixData from 'wix-data';
import wixLocation from 'wix-location';

//-------------Page Setup-------------//

$w("#dynamicDataset").onReady(async function () {
 let currentFilm = await $w('#dynamicDataset').getCurrentItem();
    console.log(currentFilm); 
    loadRelatedFilms(currentFilm);
});

// Load the films that are related to the currently displayed film.
async function loadRelatedFilms(currentFilm) {
 // Get the related film results using the rrelatedFilmsByMood() and relatedFilmsByGenre() functions.
 let relatedFilmResults = await Promise.all([
        relatedFilmsByMood(currentFilm),
        relatedFilmsByGenre(currentFilm)
    ]);

 // If there are related films found in the "Film Submission" collection:    
 if (relatedFilmResults[0].length > 0)
 // Show the related films from the collection.
        showRelatedFilms(relatedFilmResults[0]);
 // If there are no related films found in the "Film Submission" collection: 
 else
 // Fallback to showing the related films by genre.
        showRelatedFilms(relatedFilmResults[1]);
}

async function relatedFilmByRuntime(currentFilm) {
 let filmId = currentFilm._id;

 // find related films by runtime lesser or equal to 4 minutes
 let relatedByRuntime = await wixData.query('Film Collection')
  .le('filmRuntime', 4)
  .ne('_id', filmId)
  .find();
 return relatedByRuntime.items;
}

////////////////////////////////////////////////////////////////////////
// NEED HELP TO MODIFY THIS SECTION //
////////////////////////////////////////////////////////////////////////

// Get related films based on the relations set in the "Film Submissions" collection.
async function relatedFilmsByCollection(product) {
 // Get the current product's ID.
 let productId = product._id;

 // Find related products in the relationship collection by querying for related products in both relation directions.
 let relatedByTable = await Promise.all([
        wixData.query('related-products')
        .eq('productA', productId)
        .include('productB')
        .find(),
        wixData.query('related-products')
        .eq('productB', productId)
        .include('productA')
        .find()
    ]);

 // Merge related products found from both sides of the relationship collection.
 let relatedFilms = [
        ...relatedByTable[0].items.map(_ => _.productB),
        ...relatedByTable[1].items.map(_ => _.productA)
    ];

 //Return the related products found in the collection.
 return relatedFilms;
}

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

// Show the related films on the page.
function showRelatedFilms(relatedFilms) {
 // If there are any related films:
 if (relatedFilms.length > 0) {
 // Remove all but the first four related films.
        relatedFilms.splice(4, relatedFilms.length);
 // Set the function that runs when the related films repeater data is loaded to be relatedItemReady().
        $w('#relatedFilmsRepeater').onItemReady(relatedItemReady);
 // Set the related films repeater data to the first four related films.
        $w("#relatedFilmsRepeater").data = relatedFilms;
 // Expand the related films repeater.
        $w("#relatedFilms").expand();
    }
 // If there are no related films:
 else {
 // Collapse the related films repeater.
        $w("#relatedFilms").collapse();
    }
}

// Set up the related items repeater as its data is loaded.
function relatedItemReady($w, currentFilm){
// Populate the repeater elements from the item data.
 $w("#relatedFilm").src = currentFilm.linkToFilm;
 $w("#relatedTitle").text = currentFilm.FilmTitle;
 $w("#relatedLogline").text = currentFilm.FilmLogline;
 // Set the action that occurs when the video is clicked.
 $w('#relatedFilm').onClick(() => {
 // Navigate to the related film's page.
  loadRelatedFilms(currentFilm);
  wixLocation.to(currentFilm.filmPageUrl);
 });
}

I’m new to coding, so I tried following the Wix Corvid example on “related items.” However, from what I understand, in their example, they created a new collection called “related-products” where they manually created a relationship between products.

In my case, the films are submitted into the collection using a form. I would rather not have to manually create a relationship between all films, so I’m not sure how to proceed.

Is there a way to query the Selected Tags and display films that have the most tags in common? Do I need to create two new reference collections, one with all the genres and one with all the moods?

Any help is appreciated!

Wix Corvid example:

Thank you!
Natasha

Hello.

You don’t need to create a new collection when using a custom database and tags field. This related blog posts example is more suited to your case as it uses hashtags: https://www.wix.com/corvid/example/related-posts

Good luck!

Hi Sam,

Thank you for your response!

The example you shared was very helpful, but unfortunately I’m still having a bit of trouble figuring it out.

I would like to add a “recommended films” section at the bottom of the dynamic page that shows films with the most amount of similar moods and genres. If there are no results, then I display films with a runtime lesser or equal to 4 minutes.

→ Using .count(), I’d like to count the number of similar selected tags (NOT the number of FILMS that have similar selected tags).
→ Using .descending(), I’d like to organize the results.

I’m not sure that’s what my code is doing - am I missing something?

Here is my updated code:

import wixData from 'wix-data';
import wixLocation from 'wix-location';

let currentFilm;
let filmId = currentFilm._id;

$w("#dynamicDataset").onReady(async function () {
 let currentFilm = await $w('#dynamicDataset').getCurrentItem();
    console.log(currentFilm); 
    loadRelatedFilms(currentFilm);
});

async function relatedFilmByRuntime(currentFilm) {
 let relatedByRuntime = await wixData.query('Film Collection')
  .ne('_id', filmId)
  .le('filmRuntime', 4)
  .find()
 return relatedByRuntime.items;
}


function relatedFilmsByTags(currentFilm) {

 let moodQuery = wixData.query('Film Collection')
    .ne("_id", filmId)
    .hasSome("moods", currentFilm.moods)
    .find()
    .count()
    .then( (num) => {
 let numberOfItems = num;
  } );

 let genreQuery = wixData.query('Film Collection')
    .ne("_id", filmId)
    .hasSome("genres", currentFilm.genres)
    .find()
    .count()
    .then( (num) => {
 let numberOfItems = num;
  } );
 
 let tagsQuery = moodQuery.and(genreQuery)
    .ne("_id", filmId)
    .find()
    .descending()
 
 return relatedFilmsByTags.items;
};


async function loadRelatedFilms(currentFilm) {
 let relatedFilmResults = await Promise.all([
        relatedFilmsByTags(currentFilm),
        relatedFilmsByRuntime(currentFilm)
    ]);
 
 if (relatedFilmResults[0].length > 0)
        showRelatedFilms(relatedFilmResults[0]);

 else
        showRelatedFilms(relatedFilmResults[1]);
}


function showRelatedFilms(relatedFilms) {
 if (relatedFilms.length > 0) {
        relatedFilms.splice(4, relatedFilms.length);
        $w('#relatedFilmsRepeater').onItemReady(relatedItemReady);
        $w("#relatedFilmsRepeater").data = relatedFilms;
        $w("#relatedFilms").expand();
    }
 else {
        $w("#relatedFilms").collapse();
    }
}

function relatedItemReady($w, currentFilm){
 $w("#relatedFilm").src = currentFilm.linkToFilm;
 $w("#relatedTitle").text = currentFilm.FilmTitle;
 $w("#relatedLogline").text = currentFilm.FilmLogline;
 $w('#relatedFilm').onClick(() => {
  loadRelatedFilms(currentFilm);
  wixLocation.to(currentFilm.filmPageUrl);
 });
}

References:

Thank you!
Natasha