Mike K
Mike K

Reputation: 6501

Getting an error, 'Can't convert from BSON type objectId to String' when using MongoDB aggregation

I am trying to get the last message of every single conversation between User 1 and User N.

I've managed to compile the below together, however it is throwing the above, aforementioned error. How can I solve this, with ObjectIds, as that is what I have in the DB, not strings?

    await MostRecentMessages.aggregate(
      [
        {
          $match: {
            $or: [
              { from: mongoose.Types.ObjectId(id) },
              { to: mongoose.Types.ObjectId(id) }
            ],
            deletedBy: { $ne: id }
          }
        },
        { $sort: { date: -1 } },
        { $project: { _id: 1, from: 1, to: 1, conversation: 1, date: 1 } },
        {
          $group: {
            _id: {
              lastMessage: {
                $cond: [
                  {
                    $gt: [
                      { $substr: ["$to", 0, 1] },
                      { $substr: ["$from", 0, 1] }
                    ]
                  },
                  { $concat: ["$to", " and ", "$from"] },
                  { $concat: ["$from", " and ", "$to"] }
                ]
              }
            },
            conversation: { $first: "$$ROOT" }
          }
        },
        {
          $lookup: {
            from: "conversations",
            localField: "conversation",
            foreignField: "_id",
            as: "conversation"
          }
        },
        { $unwind: { path: "$conversation" } },
        {
          $lookup: {
            from: "users",
            localField: "to",
            foreignField: "_id",
            as: "to"
          }
        },
        { $unwind: { path: "$to" } },
        {
          $lookup: {
            from: "users",
            localField: "from",
            foreignField: "_id",
            as: "from"
          }
        },
        { $unwind: { path: "$from" } }
      ],
      function(err, docs) {
        if (err) {
          console.log(err);
        } else {
          console.log("MostRecentMessages", docs);
          return res.json(docs);
        }
      }
    );

My schema, if it matters:

const MostRecentMessageSchema = new Schema({
  to: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "user"
  },
  from: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "user"
  },
  conversation: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "conversation"
  },
  deletedBy: {
    type: [String]
  },
  date: {
    type: Date,
    default: Date.now
  }
});

Edit

Here are the 5 relevant documents:

// db.MostRecentMessages

_id:5dca7a61e95bd3341cad64b9
to:5dca58c21825d8269a32cb10
from:5dca58ce1825d8269a32cb11
conversation:5dca7aea51b626350fa865dd
date:2019-11-12T09:24:49.906+00:00

_id:5dca7ab0d3a44a34c98b7263
to:5dca58ce1825d8269a32cb11
from:5dca58c21825d8269a32cb10
conversation:5dca7ab0d3a44a34c98b7262
date:2019-11-12T09:26:08.125+00:00
// db.Conversation

_id:5dca7a61e95bd3341cad64b8
text:"Test1"
user:5dca58ce1825d8269a32cb11 // sender
recipient:5dca58c21825d8269a32cb10
createdAt:2019-11-12T09:24:49.827+00:00

_id:5dca7ab0d3a44a34c98b7262
text:"Test2"
user:5dca58c21825d8269a32cb10 // sender
recipient:5dca58ce1825d8269a32cb11
createdAt:2019-11-12T09:26:08.105+00:00

_id:5dca7aea51b626350fa865dd
text:"Test3"
user:5dca58ce1825d8269a32cb11 // sender
recipient:5dca58c21825d8269a32cb10
createdAt:2019-11-12T09:27:06.562+00:00

I copied and pasted the answer below, but it only returns the message with text Test2

Upvotes: 0

Views: 942

Answers (1)

matthPen
matthPen

Reputation: 4363

Link in comment is for your own knowledge... Now let's see what is working (it will probably sounds like 'deja vu' for you, but it works!). All (and your aforementioned error) take place in $group stage

db.lastMessage.aggregate([
  {
    $match: {
      $or: [
        {
          from: ObjectId("5a934e000102030405000001")
        },
        {
          to: ObjectId("5a934e000102030405000001")
        }
      ],
      deletedBy: {
        $ne: ObjectId("5a934e000102030405000001")
      }
    }
  },
  {
    $sort: {
      date: -1
    }
  },
  {
    $project: {
      _id: 1,
      from: 1,
      to: 1,
      conversation: 1,
      date: 1
    }
  },
  {
    $group: {
      _id: {
        userConcerned: {
          $cond: {
            if: {
              $eq: [
                "$to",
                ObjectId("5a934e000102030405000001")
              ]
            },
            then: "$to",
            else: "$from"
          }
        },
        interlocutor: {
          $cond: {
            if: {
              $eq: [
                "$to",
                ObjectId("5a934e000102030405000001")
              ]
            },
            then: "$from",
            else: "$to"
          }
        }
      },
      from: {
        $first: "$from"
      },
      to: {
        $first: "$to"
      },
      date: {
        $first: "$date"
      },
      conversation: {
        $first: "$conversation"
      }
    }
  },
  {
    $lookup: {
      from: "conversations",
      localField: "conversation",
      foreignField: "_id",
      as: "conversation"
    }
  },
  {
    $unwind: {
      path: "$conversation"
    }
  },
  {
    $lookup: {
      from: "users",
      localField: "to",
      foreignField: "_id",
      as: "to"
    }
  },
  {
    $unwind: {
      path: "$to"
    }
  },
  {
    $lookup: {
      from: "users",
      localField: "from",
      foreignField: "_id",
      as: "from"
    }
  },
  {
    $unwind: {
      path: "$from"
    }
  }
])

You can verify here . I just modified your group stage with the one i already provided in your other question.

Upvotes: 1

Related Questions