MongoDB 3.4.5: Hyphen-Minus does not work with $text searches

Question

I use MongoDB, Version 3.4.5 and I tried to exclude a term with -(minus). For any reason it does not work. These are my tries:

db.Product.find()
    { "_id" : ObjectId("59cbfcd01889a9fd89a3565c"), "name" : "Produkt Neu", ...
    { "_id" : ObjectId("59cc7d941889a4f4c2f43b14"), "name" : "Produkt2", ...

db.Product.find( { $text: { $search: 'Produkt -Neu' } } );

db.Product.find( { $text: { $search: "Produkt -Neu" } } );

db.Product.find( { $text: { $search: "Produkt2" } } );
    { "_id" : ObjectId("59cc7d941889a4f4c2f43b14"), "name" : "Produkt2", ...

db.Product.dropIndexes()

db.Product.createIndex({ name: "text" })
    {
        "nIndexesWas" : 2,
        "msg" : "non-_id indexes dropped for collection",
        "ok" : 1
    }

    {
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
    }

db.Product.find( { $text: { $search: "Produkt -Neu" } } );

db.Product.find( { $text: { $search: "Produkt Neu" } } );
    { "_id" : ObjectId("59cbfcd01889a9fd89a3565c"), "name" : "Produkt Neu", ...

Does anyone know what I have to do in order to get it work with -(minus).


Show source
| search   | mongodb   2017-09-28 09:09 1 Answers

Answers to MongoDB 3.4.5: Hyphen-Minus does not work with $text searches ( 1 )

  1. 2017-10-01 11:10

    I created a collection: Product with the following documents ...

    {
        "_id" : ObjectId("59d0ada3c26584cd8b79fc51"),
        "name" : "Produkt Neu"
    }
    
    {
        "_id" : ObjectId("59d0adafc26584cd8b79fc54"),
        "name" : "Produkt2"
    }
    

    ... and I declared a text index on this collection as follows:

    db.Product.createIndex({ name: "text" })
    

    I ran the following queries which faithfully reproduce the situation described in your question:

    // returns one document since there is one document 
    // which has the text indexed value: "Produkt Neu"
    db.Product.find( { $text: { $search: "Produkt Neu" } } );
    
    // returns no documents since there is no document 
    // which has the text indexed value: "Produkt2"
    db.Product.find( { $text: { $search: "Produkt -Neu" } } )
    

    You are, I think, expecting this query ...

    db.Product.find( { $text: { $search: "Produkt -Neu" } } )
    

    ... to return the second document on the grounds that excluding Neu should allow a match on the document having name=Produkt2 but this is not how MongoDB $text searches work. MongoDB $text searches do not support partial matching so the search term Produkt -Neu (which evaluates as Produkt) will not match Produkt2. To verify this, I ran the following query:

    db.Product.find( { $text: { $search: "Produkt2 -Neu" } } ) 
    

    This query returns the second document (i.e. the one with name=Produkt2) which proves that the hyphen-minus (-) successfully negated the term: Neu.

    On a side note; MongoDB text indexes do support language stemming, to verify this behaviour I added the following document...

    {
        "_id" : ObjectId("59d0b2b4c26584cd8b79fd7c"),
        "name" : "Produkts"
    }
    

    ...and then ran this query ...

    db.Product.find( { $text: { $search: "Produkt -Neu" } } );
    

    This query returns the document with name=Produkts because Product is a stem of Produkts.

    In summary, a $text search will find matches where each search term has either (a) a match on a whole world in the text index or (b) is a recognised stem of a whole word in the text index. Note: there are also phrase matches but those are not relevant to the examples in your question. Use of the hyphen-minus serves to change the search terms but it does not change how the search term is evaluated.

    More details in the docs and there is an open issue with MongoDB relating to supporting partial matching on text indexes.

    If you really need to support partial matching then you'll probably want to discard the text index and use the $regex operator instead. Though it's worth noting that index coverage with the $regex operator is probably not what you expect, the brief summary is this: if your search value is anchored (i.e. Produk, rather than rodukt) then MongoDB can use an index but otherwise it cannot.

Leave a reply to - MongoDB 3.4.5: Hyphen-Minus does not work with $text searches

◀ Go back