summaryrefslogtreecommitdiff
path: root/jstests/core/fts_projection.js
blob: 50fe4755fc3e1fb667b8186f9415aeba9abdfe8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Test $text with $textScore projection.

var t = db.getSiblingDB("test").getCollection("fts_projection");
t.drop();

db.adminCommand({setParameter: 1, newQueryFrameworkEnabled: true});

t.insert({_id: 0, a: "textual content"});
t.insert({_id: 1, a: "additional content", b: -1});
t.insert({_id: 2, a: "irrelevant content"});
t.ensureIndex({a: "text"});

// Project the text score.
var results = t.find({$text: {$search: "textual content -irrelevant"}},
                     {_idCopy: 0, score: {$meta: "textScore"}}).toArray();
// printjson(results);
// Scores should exist.
assert.eq(results.length, 2);
assert(results[0].score);
assert(results[1].score);

// indexed by _id.
var scores = [0, 0, 0];
scores[results[0]._id] = results[0].score;
scores[results[1]._id] = results[1].score;

//
// Edge/error cases:
//

// Project text score into 2 fields.
results = t.find({$text: {$search: "textual content -irrelevant"}},
                 {otherScore: {$meta: "textScore"}, score: {$meta: "textScore"}}).toArray();
assert.eq(2, results.length);
for (var i = 0; i < results.length; ++i) {
    assert.close(scores[results[i]._id], results[i].score);
    assert.close(scores[results[i]._id], results[i].otherScore);
}

// printjson(results);

// Project text score into "x.$" shouldn't crash
assert.throws(function() {
    t.find({$text: {$search: "textual content -irrelevant"}}, {'x.$': {$meta: "textScore"}})
        .toArray();
});

// TODO: We can't project 'x.y':1 and 'x':1 (yet).

// Clobber an existing field and behave nicely.
results =
    t.find({$text: {$search: "textual content -irrelevant"}}, {b: {$meta: "textScore"}}).toArray();
assert.eq(2, results.length);
for (var i = 0; i < results.length; ++i) {
    assert.close(
        scores[results[i]._id],
        results[i].b,
        i + ': existing field in ' + tojson(results[i], '', true) + ' is not clobbered with score');
}

assert.neq(-1, results[0].b);

// Don't crash if we have no text score.
var results = t.find({a: /text/}, {score: {$meta: "textScore"}}).toArray();
// printjson(results);

// No textScore proj. with nested fields
assert.throws(function() {
    t.find({$text: {$search: "blah"}}, {'x.y': {$meta: "textScore"}}).toArray();
});

// SERVER-12173
// When $text operator is in $or, should evaluate first
results = t.find({$or: [{$text: {$search: "textual content -irrelevant"}}, {_id: 1}]},
                 {_idCopy: 0, score: {$meta: "textScore"}}).toArray();
printjson(results);
assert.eq(2, results.length);
for (var i = 0; i < results.length; ++i) {
    assert.close(scores[results[i]._id],
                 results[i].score,
                 i + ': TEXT under OR invalid score: ' + tojson(results[i], '', true));
}

// SERVER-12592
// When $text operator is in $or, all non-$text children must be indexed. Otherwise, we should
// produce
// a readable error.
var errorMessage = '';
assert.throws(function() {
    try {
        t.find({$or: [{$text: {$search: "textual content -irrelevant"}}, {b: 1}]}).itcount();
    } catch (e) {
        errorMessage = e;
        throw e;
    }
}, null, 'Expected error from failed TEXT under OR planning');
assert.neq(-1,
           errorMessage.message.indexOf('TEXT'),
           'message from failed text planning does not mention TEXT: ' + errorMessage);
assert.neq(-1,
           errorMessage.message.indexOf('OR'),
           'message from failed text planning does not mention OR: ' + errorMessage);

// Scores should exist.
assert.eq(results.length, 2);
assert(results[0].score,
       "invalid text score for " + tojson(results[0], '', true) + " when $text is in $or");
assert(results[1].score,
       "invalid text score for " + tojson(results[0], '', true) + " when $text is in $or");