MongoDB lookup with match not efficient in large amount of data - mongodb

I have a two collection that systems and systemsToUsers. It is refer the systems _id as a foreign key system_id in a systemToUsers table. I need system data which all are _id not presents in the sytemToUser table.
I am using the below query but it is taking a long time (5 seconds) for 100 000 data. But need to optimize the query reduce the execution time
db.Systems.aggregate([
{ $lookup: {
from: 'systemsToUsers',
localField: '_id', foreignField: 'system_id',
as: 'systemswithusers' } },
{ $match: { $expr: { $eq: [ { $size: '$systemswithusers' }, 0 ] } } }
]);

Try below $match and make sure every column in aggregate have index.
db.Systems.aggregate([
{
$lookup: {
from: "systemsToUsers",
localField: "_id",
foreignField: "system_id",
as: "systemswithusers"
}
},
{
$match: {
systemswithusers: []
}
}
])
mongoplayground

Related

MongoDB $lookup - conditional value for localfield?

I have 2 collections I want to combine using lookup.
Collection1: _AddressSyncStatus
fields I wanna use from this collection: "address"
Collection2: EthTokenTransfers
Fields I want to use from this collection: "to_address", "from_address".
Now when I use mongo compass, the lookup filter expects a local field, in my case the local field of EthTokenTransfers to join the collections. My problem now is, that I want to lookup where address from _AddressSyncStatus is either EthTokenTransfers.from_address OR EthTokenTransfers.to_address.
Is this possible using aggregations?
{
from: '_AddressSyncStatus',
localField: 'string', //from_address OR to_address
foreignField: 'address',
as: 'synced_address'
}
One way to do it is using the $lookup pipeline with $or:
db.EthTokenTransfers.aggregate([
{
$lookup: {
from: "_AddressSyncStatus",
let: {
from_address: "$from_address",
to_address: "$to_address"
},
pipeline: [
{
$match: {
$expr: {$or: [{$eq: ["$_id", "$$from_address"]},
{$eq: ["$_id", "$$to_address"]}
]
}
}
}
],
as: "synced_address"
}
}
])
As you can see here.
But I think that for the rset of the work with this data, it will be more convenient like this:
db.EthTokenTransfers.aggregate([
{
$lookup: {
from: "_AddressSyncStatus",
localField: "from_address",
foreignField: "_id",
as: "synced_address_from"
}
},
{
$lookup: {
from: "_AddressSyncStatus",
localField: "to_address",
foreignField: "_id",
as: "synced_address_to"
}
}
])
As you can see here

MongoDB $lookup creates array

So I am trying to join two collections together:
Collections are:
shows
episodes
I am using the $lookup value inside the shows collection.
[{$lookup: {
from: 'episode',
localField: 'url',
foreignField: 'show_b',
as: 'match_docs'
}}]
However I am getting all of the episodes from each show inside the match_docs in theory that is fine, however I need to be able to limit it to the latest episode limit:1 for each show ordered by pubDate
If anyone knows how I could limit the match_docs to only lookup once that would be great
I have also tried
{
from: 'episode',
localField: 'url',
foreignField: 'show_b',
pipeline: [
{$sort:{id:1}},{$limit:1},
],
as: 'match_docs'
}
With no success.
That would be easy with the second syntax of $lookup:
[
{
$lookup: {
from: 'episodes', # make sure your collection name is correct
let: {url: '$url'},
pipeline: [
{
$match: {
$expr: {
$eq: ['$show_b', '$$url']
}
}
},
{
$sort: {
pubDate: -1
}
},
{
$limit: 1
}
],
as: 'match_docs'
}
}
]

MongoDB aggregate - lookup if the only minimum number of documents matches

I Have a collection called "cv" and another collection called "sections"
In the collection "section" I have a field called "ownerCV" which refers to the CV ID
I want to get the CVs which have a minimum of 4 sections
I use
([
{
$lookup: {
from: UserSection.tableName,
localField: '_id',
foreignField: 'ownerCV',
as: 'sections'
}
}, {
$project: {
sectionsCount: {
$size: '$sections'
}
}
}, {
$match: {
'sectionsCount': {
'$gte': 4
}
}
}
])
.skip(count * page)
.limit(count)
.toArray();
But it takes a big time.
So is there another way i can do that in a fast time?

MongoDB Merge two properties from different collections into one and sort them

I'm faced into the issue when I'm trying to merge the results of two MongoDB lookup's into one property, and then I want to unwind them and sort.
I have a problem with merging the results of lookup's.
Here is the actual code:
db.getCollection('collectionA').aggregate([
{
$lookup:
{
from: 'collectionB',
localField: "_id",
foreignField: "collectionAKey",
as: "collectionBInfo"
}
},
{
$lookup:
{
from: 'collectionC',
localField: "_id",
foreignField: "collectionAKey",
as: "collectionCInfo"
}
},
/// then I just want to create one property from both of lookup's, unwind them and sort by the timestamp
{
$unwind: "$mergedCollectionsAandB"
},
{
$sort: {
"mergedCollectionsAandB.timestamp": -1
}
}
])
Here is a models of collections:
CollectionA
_id
name
CollectionB
_id
timestamp
collectionAKey
CollectionC
_id
timestamp
collectionAKey
I assume that it's possible by using $mergeObjects MongoDB operator, but I'm stuck a little bit how to do it in a right way. Is that possible? Thanks in advance.
So the final version of my query looks like that, it's what I was looking for:
db.getCollection('collectionA').aggregate([
{
$lookup:
{
from: 'collectionB',
localField: "_id",
foreignField: "collectionAKey",
as: "collectionBInfo"
}
},
{
$lookup:
{
from: 'collectionC',
localField: "_id",
foreignField: "collectionAKey",
as: "collectionCInfo"
}
},
{
$project: {
"mergedCollectionsAandB": { $concatArrays: ["$collectionBInfo", "$collectionCInfo"] }
}
},
{
$unwind: "$mergedCollectionsAandB"
},
{
$sort: {
"mergedCollectionsAandB.timestamp": -1
}
}
])

some questions about Aggregate running mechanism

Aggregate1:
db.collection.aggregate([
{
$lookup: {
...
}
},
{
$limit: 1
}
])
Aggregate2:
db.collection.aggregate([
{
$limit: 1
},
{
$lookup: {
...
}
}
])
Aggregate1 and Aggregate2 are different?
In Aggregate1,is the whole collection scanned firstly, then do $lookup?
If it is different,how to lookup with some query?just like this:
db.collection.aggregate([
{
$lookup: {
from: 'collection2',
localField: 'field',
foreignField: 'field',
as: 'newField',
// do some query when lookup
query: {'newField.xxx': 1}
}
}
])
I know, i can do this:
db.collection.aggregate([
{
$lookup: {
from: 'collection2',
localField: 'field',
foreignField: 'field',
as: 'newField'
}
},
{$unwind: '$newField'},
{$match: {'newField.xxx': 1}}
])
But I'm afraid that, like the example above, the entire collection will be scanned。
Look forward to your reply!
Now,i find this api:$graphLookup.restrictSearchWithMatch,but:
NOTE
You cannot use any aggregation expression in this filter.
For example, a query document such as
{ lastName: { $ne: "$lastName" } }
will not work in this context to find documents in which the lastName
value is different from the lastName value of the input document,
because "$lastName" will act as a string literal, not a field path.