I have an aggregate query that extracts sub-documents from a database in mongodb:
[
{
$match: {
username: query.username,
},
},
{
$project: {
connections: {
$filter: {
input: '$connections',
as: 'connections',
cond: {
$eq: ['$$connections.state', query.state],
},
},
},
},
}
]
The document schema looks as the following (from typegoose, but fairly self explanatory):
export class Connection {
@prop({ default: () => new Date() })
public updated?: Date;
@prop({ required: true, enum: ConnectionStateEnum })
public state: ConnectionStateEnum;
@prop({ required: true })
public username: string;
@prop()
public requestIP?: string;
@prop()
public requestBrowserString?: string;
}
@modelOptions({
schemaOptions: {
collection: 'connections',
timestamps: true,
},
})
export class UserConnections {
@prop({ default: v1 })
/* tslint:disable */
_id: string;
/* tslint: enable */
@prop({ unique: true })
username: string;
@prop({ required: true })
lastConnectionActivityWithUsername: string;
@arrayProp({ items: Connection })
connections: Connection[];
}
The idea is a user has 1 doc containing their connections, thus the connections attribute is an array of connection objects.
If i add a $skip or $limit to the aggregate query this will not change the result of the query as this limits the qty of docs returned, but as there is a macth on a unique field the doc count will always be 1.
Is it possible to limit/skip the number of connection objects to return from a single doc within the query, or can this only be done post query?
(eg a user has 20 connections, but i only want to return 10 connections from the doc)
Based on the answer below I arrived at mixin slice and filter into a $let aggregation pipeline operator as using slice next $filter failed with an error of:
MongoError: Invalid $project :: caused by :: an expression specification must contain exactly one field, the name of the expression. Found 2 fields in { $filter: { input: "$connections", as: "connections", cond: { $eq: [ "$$connections.state", "requestSentAccepted" ] } }, $slice: [ "$$connections", 0, 20 ] }, while parsing object { connections: { $filter: { input: "$connections", as: "connections", cond: { $eq: [ "$$connections.state", "requestSentAccepted" ] } }, $slice: [ "$$connections", 0, 20 ] }
This worked though:
{
$project: {
connections: {
$let: {
vars: {
connections: {
$filter: {
input: '$connections',
as: 'connections',
cond: {
$eq: ['$$connections.state', query.state],
},
},
},
},
in: {
$slice: ['$$connections', offset, limit],
},
},
},
},
},