简体   繁体   中英

How to write a mongoDB query to match any element in an array of subdocuments against any element in a Typescipt Array?

I have a mongoDB database containing Events . Each event is defined by a number of fields, including an array of genres (which are subdocuments consisting of a {genre and subGenre}).

For example: an event could be of {genre: "music", subGenre: "jazz"}, and {genre: "music", subGenre: "blues"}. See event.js - the model. In this case, 2 "genre" sub documents are added to the "genres" array in the Event document in the database.

Back in my node application - see query.ts - I am trying to work out how to run a query that lets the user search for all events that match their genre preferences.

So:

  • the Event is defined by an array of genres (in the database), and
  • the user's preferences are defined by an array of genres (in the
    application).

I am looking to define a mongoDB query that returns all Events where there is a match of any 1 {genre, subGenre} combination between the 2 arrays.

I looked into $in Query Selector in the mongoDB documentation and suspect it might need to be used... but programmatically, how do I write a query that expands to include all the values in the variable "searchGenres" in query.ts ?

Thanks a lot in advance for your thoughts.


event.js: mongoDB Model for 'Events" defined using Mongoose - snippet:

let mongoose    = require('mongoose');

let EventSchema = new mongoose.Schema({

genres: [
          {
            genre:      String,
            subGenre:   String
          }
       ]
)};

module.exports =  mongoose.model('Event', EventSchema);

query.ts:

import mongoose   = require('mongoose');
let Event         = require ('../models/event');

class Genre {
    genre:      string;
    subGenre:   string;

    constructor (gen: string, sub: string) {
        this.genre      = gen;
        this.subGenre   = sub;
    }
}

async function runQuery()
{
    let searchGenres : Array<Genre> = new Array<Genre>();

    // populate searchGenres with some data here... e.g.
    const searchGenre1 : Genre = new Genre ('music', 'jazz');
    const searchGenre2 : Genre = new Genre ('music', 'rock');

    searchGenres.push(searchGenre1);
    searchGenres.push(searchGenre2);

    // Query logic here:
    // Return all events from the database, if the 'genres' array
    // in the document matches any element in the searchGenres array
    // defined above..

    const events = await Event.find ({
                                       'genres': {?help? }

                                    });

}
```

After some self-education today, I have come up with a solution, which I am happy with - to append to end of query.ts:

type GenreQuerySelector = { genres: { $elemMatch: { 'genre': string; 'subGenre': string; }; }; };

let querySelectors : Array< GenreQuerySelector > = new Array< GenreQuerySelector >();

for (let genre of searchGenres) {

    const genreQuery : GenreQuerySelector = {
        genres: {
                    $elemMatch: {
                                    'genre':    genre.genre,
                                    'subGenre': genre.subGenre
                                }
                }
     };        
     querySelectors.push(genreQuery);
};

const events = await Event.find  ({ $or: querySelectors }).exec();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM