Reputation: 153
I want to fetch the result using $lookup having local fields as the array of _id as a string. But its not happening. I also tried by using _id.str but still no results.
db.posts.aggregate([
{
$addFields: {
TagCount: { $size: "$tags" }
}
},
{
$lookup:
{
from: "tags",
localField: "tags",
foreignField: "_id",
as: "tagList"
}
},
]));
The schema for Post Collection
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true,
minlength: 10,
set: v => v.replace(/\s\s+/gi, ' '),
get: v => { console.log(v); return v.replace(/\s\s+/gi, ' '); }
},
content: {
type: String,
required: true
},
headerImage: {
type: String
},
tags: [{
type: mongoose.Schema.Types.ObjectId,
required: true,
validate: {
validator: function (v) {
return v.length > 0;
}
},
message: 'There must be one tag',
ref: 'tags'
}],
creationDate: { type: Date, default: Date.now }
});
Here is the tag Schema Collection
const tagSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 3,
set: value => value.replace(/\s\s+/gi, ' '),
get: value => value.replace(/\s\s+/gi, ' ')
},
description: {
type: String
},
creationDate: {
type: Date,
default: Date.now
}
}, {
collection: 'tags'
});
Also, I tried other StackOverflow questions but I didn't find any solutions.
Upvotes: 0
Views: 1927
Reputation: 1
db.posts.aggregate([
{
$lookup: {
from: "tags",
let: { pid: "$tags" },
pipeline: [
{
$match: {
$expr: {
$eq: ["$_id", { $toObjectId: "$$pid" }]
}
}
}
],
as: "tagList"
}]);
Upvotes: 0
Reputation: 28316
Including the ref: 'tags'
in the schema definition for the tags
array makes mongoose store the values as DBRef, not ObjectID.
This is useful if you intend to use the populate
function to retrieve the tag documents on the client side.
The field names in an aggregation are $id
, $ref
, and $db
, which are not valid field names when using dotted notation, like you need to do in the aggregation pipeline.
You could convert each object to an array, which would make it look something like [ {"k":"$id", v:ObjectId("...")}, {"k":"$ref","v":"tags"}, {"k":"$db","v":"dbname"}]
Then filter for the $id
key, retain the corresponding value, and use that array as the local field.
db.posts.aggregate([
{$addFields: {
TagCount: {$size: "$tags"},
tag_ids: {
$map: {
input: "$tags",
as: "dbref",
in: {
$reduce: {
input: {$objectToArray: "$$dbref"},
initialValue: [],
in: {
$cond: {
if: {$eq: ["$$this.k",{$literal: "$id"}]},
then: "$$this.v",
else: "$$value"
}
}
}
}
}
}
}},
{
$lookup: {
from: "tags",
as: "tag_list",
localField: "tag_ids",
foreignField: "_id"
}
}
])
Upvotes: 1