0

I have the following function:

public function cmd(Array $cmd){
    if ($this->ready_to_act()){
        $comando = [
            'aggregate' => $this->collection,
            'pipeline' => [
                [
                    '$concat'=>[
                        'final_value'=>[
                            '$first',
                            ' ',
                            '$last'
                        ]
                    ]
                ],
                [
                    '$match'=>[
                        'final_value'=> new MongoDB\BSON\Regex("/$texto/",'gi')
                    ]
                ]
            ]
        ];
        $command = new MongoDB\Driver\Command($cmd);
        return $this->link
                    ->executeCommand($this->database,$command);
    }else{
        throw new MongoDB\Driver\Exception\InvalidArgumentException("No hay base de datos/coleccion definida!");
        die();
    }
}

I'm trying to run a command that concat the first and last "columns", and check if final value is like $texto.

But something is wrong. In PHP Documentation there is nothing about $concat.

Unrecognized pipeline stage name: '$concat'

I don't know what to do, what am i doing wrong

For me, it's not allowed to use Composer.

1
  • You're actually doing a lot of things wrong, starting with using the wrong driver. You actually want the PHPLIB driver, as what you have downloaded is the "low level" interface for driver developers. Install and use the correct driver and follow all the regular examples where there is actually a Collection::aggregate() method Commented Oct 19, 2017 at 22:42

1 Answer 1

2

Wrong Driver

As noted, you are using the wrong driver to start with. So the very first thing to do is install the correct driver as documented. If you are still confused about which driver is which, then there is this page on php.net with a diagram explaining it all.

You really should install and use the correct driver because that is the one that is intended for usage in your application space. The low level interface you presently have is for driver software developers who already know what they are doing, and are implementing integrated features for frameworks at a very low level.

Correct Pipeline

The basic error being thrown though it because $concat is not a "pipeline stage". It's an operator for usage inside pipeline stages such as $project or $addFields, which is how you meant to use it in this context:

$pipeline = [
  [ '$addFields' => [
    'final_value' => [
      '$concat' => [ '$first', ' ', '$last' ]
    ]
  ]],
  [ '$match'=>[
    'final_value'=> new MongoDB\BSON\Regex("/$texto/",'gi')
  ]]
];

That's the correct way to define the pipeline. If you don't have $addFields ( from MongoDB 3.2, which really should be the minimal version you have installed by now Note ) then you use $project and define "all" of the document properties you want to receive in addition.

As a point of trivia, if you have MongoDB 3.4 then you "could" use $indexOfCP within a $redact pipeline stage instead:

$pipeline = [
  [ '$redact' => [
    '$cond' => [
      'if' => [
        '$ne' => [
          [ '$indexOfCP' => [
            [ '$concat' => [ '$first', ' ', '$last' ] ],
            $texto
          ]],
          -1
        ]
      ],
      'then' => '$$KEEP',
      'else' => '$$PRUNE'
    ]
  ]]
];

But I really don't think you should be doing that or the corrected aggregation pipeline you were attempting, as there is a much better way to do this with MongoDB. And of course the pipeline expressions really should be issued by using MongoDB\Collection::aggregate() in the correct driver namespace.

Alternate

In all honesty you really should be using $text search here instead. This allows you to define a "text index" over the two fields and then you can simply enter in the search term for the query.

Assuming a database namespace of "test" and a collection named "collection", you could create the index:

$collection = (new MongoDB\Client)->test->collection;
$indexName = $collection->createIndex(['first' => 'text', 'last' => 'text' ])

And then issue the query:

$collection = (new MongoDB\Client)->test->collection;

$cursor = $collection->find([
  '$text' => [ '$search' => $words_or_phrase ]
]);

foreach ($cursor as $document) {
  var_dump($document);  # do something real here
}

So the "query" does not need to know about which properties to search in because these are defined when you create the index. You can simply enter just the "words" of the name, being first or last or both and the matches will be returned, and also in order of relevance to the matches, because that is what text searches do.

Again though, you really need to be using the correct driver which quite happily returns a proper cursor and supports all additional options in a standard way.

NOTE: Official support for MongoDB versions prior to 3.2 expires as of February 2018. See Support Policy.

Sign up to request clarification or add additional context in comments.

1 Comment

I must have Composer to do it "right" but I am not allowed to use Composer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.