marklogic / node-client-api

The MarkLogic Node.js Client API
https://docs.marklogic.com/jsdoc/index.html
Apache License 2.0
52 stars 45 forks source link

Prefix binding with collection query returns 0 results #192

Closed csreddy closed 9 years ago

csreddy commented 9 years ago

Here's the test case:


var should = require('should');

var testconfig = require('../etc/test-config-qa.js');

var marklogic = require('../');
var q = marklogic.queryBuilder;

var db = marklogic.createDatabaseClient(testconfig.restReaderConnection);
var dbWriter = marklogic.createDatabaseClient(testconfig.restWriterConnection);
var dbAdmin = marklogic.createDatabaseClient(testconfig.restAdminConnection);

describe('Document parse binding test', function(){
  before(function(done){
    this.timeout(10000);
    dbWriter.documents.write({
      uri: '/test/query/matchDir/doc1.json',
      collections: ['matchCollection1'],
      contentType: 'application/json',
      content: {
        title: 'Vannevar Bush',
        popularity: 5,
        id: '0011',
        date: '2005-01-01',
        price: {
             amt: 0.1
           },
        p: 'Vannevar Bush wrote an article for The Atlantic Monthly'
        }
      }, { 
      uri: '/test/query/matchDir/doc2.json',
      collections: ['matchCollection1', 'matchCollection2'],
      contentType: 'application/json',
      content: {
        title: 'The Bush article',
        popularity: 4,
        id: '0012',
        date: '2006-02-02',
        price: {
             amt: 0.12
           },
        p: 'The Bush article described a device called a Memex'
        }
      }, { 
      uri: '/test/query/matchDir/doc3.json',
      collections: ['matchCollection2'],
      contentType: 'application/json',
      content: {
        title: 'For 1945',
        popularity: 3,
        id: '0013',
        date: '2007-03-03',
        price: {
             amt: 1.23
           },
        p: 'For 1945, the thoughts expressed in the Atlantic Monthly were groundbreaking'
        }
      }, { 
      uri: '/test/query/matchDir/doc4.json',
      collections: [],
      contentType: 'application/json',
      content: {
        title: 'Vannevar served',
        popularity: 5,
        id: '0024',
        date: '2008-04-04',
        price: {
             amt: 12.34
           },
        p: 'Vannevar served as a prominent policymaker and public intellectual',
        booleanVal: false,
        nullVal: 'not null'
        }
      }, { 
        uri: '/test/query/matchList/doc5.json',
        collections: ['matchList'],
        contentType: 'application/json',
        content: {
          title: 'The memex',
          popularity: 5,
          id: '0026',
          date: '2009-05-05',
          price: {
               amt: 123.45
             },
          p: 'The Memex, unfortunately, had no automated search feature',
          booleanVal: true,
          nullVal: null
          }
        }).
    result(function(response){done();}, done);
  });
  it('should do collection parse', function(done){
    db.documents.query(
      q.where(
        q.parsedFrom('coll:"matchCollection1"',
          q.parseBindings(
            q.collection('matchCollection1', q.bind('coll'))
          )
        )
      ).
      withOptions({
              queryPlan: true,
              metrics: false,
              debug: true
            })
    ).
    result(function(response) {     
    console.log(JSON.stringify(response, null, 4)); 
    response.length.should.equal(2);
      done();
    }, done);
  });

  it('cleanup: should delete all documents', function(done){
    dbAdmin.documents.removeAll({
      all: true
    }).
    result(function(response) {
      done();
    }, done);
  }); 
});

Here's the query plan:

 "(cts:search(fn:collection(), cts:collection-query(\"matchCollection1matchCollection1\"), (\"unfiltered\",cts:score-order(\"descending\")), 1))[1 to 10]"

The root cause is that its doing collection query on cts:collection-query(\"matchCollection1matchCollection1\") instead of cts:collection-query(\"matchCollection1\")

ehennum commented 9 years ago

Thanks for exercising the API.

I believe the test case should be:

q.parsedFrom('coll:"matchCollection1"',
      q.parseBindings(
        q.collection(q.bind('coll'))
      )
    )

When you supply a q.bind() binding on q.collection, the optional string argument is a prefix, as in:

q.parsedFrom('coll:"suffix"',
      q.parseBindings(
        q.collection(q.bind('coll'), '/prefix/')
      )
    )

yielding cts:collection-query("/prefix/suffix") as in your test case.

It would be inconvenient to have to supply the same query criteria both as part of the query text and as a query parameter.

See: http://docs.marklogic.com/jsdoc/queryBuilder.html#collection

Unless you disagree because I've misunderstood, please close the bug.

csreddy commented 9 years ago

I was kind a mislead by the similar signature of other queries, such as q.value('category', q.bind('cat')), q.word('title', q.bind('title')) and q.range(q.pathIndex('/priority/level'), q.bind('p')) which take the first parameter as the property name, so I assumed for collection, the first param must be the collection name as suggested even by the docs. Thanks Erik