alter
alter

Reputation: 23

MongoDB Nested Documents Aggregation using Change Events

The problem is that when I push a new document inside the array field it becomes a dotted notation.

What I am trying to achieve is to filter the the response of the Change Event or the Collection.watch().

This the okay version

But this happens

enter image description here

There is no way that I can access the updateDescription.updatedFields.message because it became a dot notation.

I tried to use

var filter = [{
    $match: {
        $and: [
            { 'documentKey._id': req.body.id },
            {'updateDescription.updatedFields.message': // value of current length of the messages array}
        ]
    }
  }];

and

var filter = [{
    $match: {
        $and: [
            { 'documentKey._id': req.body.id },
            {'updateDescription.updatedFields.messages' : {$exists: true}}
        ]
    }
  }];

I also used projection:

try{
    res.status(200).set({
      "connection":"keep-alive",
      "cache-control": "no-cache",
      "content-type":"application/json"
    });
  var query = await User.findOne({'_id': req.body.id});
  var len = parseInt(query['messages'].length);
  var _str = 'messages.'+String(len);
  console.log(_str)
  var project = [{$project: {'updateDescription.updatedFields' : {$objectToArray: '$updateDescription.updatedFields'}}}]
  var filter = [{
    $match: {
        $and: [
            { 'documentKey._id': req.body.id },
            {'updateDescription.updatedFields.k': _str}
        ]
    }
  }];

  await User.watch(filter, project).on('change', data => console.log(data))

  }catch(err){
    res.status(500).send(err);
  }

But still I haven't got any solution how to solve this.

Upvotes: 1

Views: 611

Answers (2)

xsephtion
xsephtion

Reputation: 193

The problem is that you are projecting it wrong.

$project: {'updateDescription.updatedFields' : {$objectToArray: '$updateDescription.updatedFields'}}

is should be

{$project: { 'updateDescription.updatedFields' : {$objectToArray: '$updateDescription.updatedFields'}, 'documentKey._id': req.body.id  }}

Then you go use regex on the $match

{$match: {
    $and: [
       { 'documentKey._id': req.body.id },
       {'updateDescription.updatedFields.k': {$regex:"^matches"}}
   ]}

Here's the full working snippet:

  try{
    res.status(200).set({
      "connection":"keep-alive",
      "cache-control": "no-cache",
      "content-type":"application/json"
    });

  var filter = [
    {$project: { 'updateDescription.updatedFields' : {$objectToArray: '$updateDescription.updatedFields'}, 'documentKey._id': req.body.id  }},
    {$match: {
        $and: [
            { 'documentKey._id': req.body.id },
            {'updateDescription.updatedFields.k': {$regex:"^matches"}}
        ]
    }
  }];

  await User.watch(filter).on('change', data => console.log(data.updateDescription.updatedFields))

  }catch(err){
    res.status(500).send(err);
  }

The reason why it's not matching is because you are using $and operator and there's no "documentKey._id" to match with since you projected it wrong.

Upvotes: 2

Joe
Joe

Reputation: 28336

The $filter and $project stages should be together in a single array. The watch function takes (Pipeline Array, Options Object). Try:

  var filter = [
    {$project: {'updateDescription.updatedFields' : {$objectToArray: '$updateDescription.updatedFields'}}},
    {$match: {
        $and: [
            { 'documentKey._id': req.body.id },
            {'updateDescription.updatedFields.k': _str}
        ]
    }
  }];

await User.watch(filter).on('change', data => console.log(data))

Upvotes: 0

Related Questions