Aggregation based many collection - mongodb

I have 3 tables like
Actor
actor_id: "1"
first_name: "Penelope"
last_name: "Guiness"
Films
film_id: "1"
title: "ABC"
Film_Actor
film_id: "1"
actor_id: "22"
I want to get movies (title) starring by an actor, like
actor_id: "1"
title: {"ABC", "DEF", "GHI"}
in this case I have not been able to get it, what I just achieved is only aggregation based on 2 collections like:
db.actor.aggregate ([
{
$ lookup:
{
from: 'film_actor',
localField: 'actor_id',
foreignField: 'actor_id',
as: 'film_id'
} }
])

First of all I think you have a data model issue there. It looks like a SQL database and that's not the idea of using mongo.
But if you want to do it anyway you should do:
db.actor.aggregate([
{
$lookup: {
from: "film_actor", // the collection you are trying to match
localField: "actor_id",
foreignField: "actor_id",
as: "film_actor"
}
},
{
$lookup: {
from: "films", // the collection you are trying to match
localField: "film_actor.film_id", // or '$film_actor.actor_id' if it does not work
foreignField: "film_id",
as: "film"
}
},
{
$group: {
_id: "$actor_id",
titles: {$push: "$film.title"}
}
}
]);
I hope you find it useful.

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

Applying $exists to MongoDB aggregation

I have two mongo collections structured like so:
customers
{
_id: ObjectId,
name: String,
companyId: ObjectId
}
companies
{
_id: ObjectId,
name: String,
rights: [
add: boolean,
edit: boolean,
shop: boolean
]
}
So each customer has a companyId that lets us look up the companies.rights available. I need to get a list of which companies have customers but don't have the shop property at all.
So far I have this:
db.getCollection('customers').aggregate([
{
$match: {}
},
{
$lookup: {
from: 'companies',
localField: 'companyId',
foreignField: '_id',
as: 'company'
}
},
{
$project: {
companyId: '$company._id',
companyName: '$company.name',
shopSetting: '$company.rights.shop'
}
}
])
This seems to be working ok to give me all of the companies with their shop value (true or false). But what if I only want to see the companies that don't have the shop field existing at all? How would I modify this query to accomplish that? I've tried reading up on the $exists field in mongo, but this is all pretty new to me so I'm not sure where to apply it here.
Note: I need to query the companies from the customers collection because there are some companies without customers and I need this result to only be companies that are assigned to customers but don't have the rights.shop property existing
db.customers.aggregate([
{ $match: {} },
{
$lookup: {
from: "companies",
localField: "companyId",
foreignField: "_id",
as: "company",
pipeline: [
{
$match: {
$expr: {
$eq: [
{
$filter: {
input: "$rights",
as: "r",
cond: "$$r.shop"
}
},
[]
]
}
}
}
]
}
},
{
$project: {
companyId: "$company._id",
companyName: "$company.name",
shopSetting: "$company.rights.shop"
}
}
])
mongoplayground

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'
}
}
]

Is there any placeholder value that can be used in a MongoDB aggregation lookup, to find the right field in an object of objects?

I have two collections, where the first one has foreign keys of the second collection. Now I want to aggregate the matching data of the second collection. The problem is, that I don't know to properly define the path of the localField, because it's in an object of objects.
It will be changed to an array of objects at some point, but for now I have to deal with it. The collection structures look like this:
collectionOne
{
_id: ObjectId('...'),
groups: {
'1': {
things: [{
id: xyz,
foreignId: ObjectID('001') // id of collectionTwo
}]
},
'2': {
things: [{
id: zyx,
foreignId: ObjectId('001') // id of collectionTwo
}]
},
}
}
collectionTwo
{
_id: ObjectID('001').
...
}
I've read through the docs and searched here and elsewhere, but I didn't find any matching case.
For arrays I know I don't have to specify the actual place in the array. So if groups would also be an array of objects I could just use the dot operator like this:
collectionOne.aggregate([
{$match: {_id, ObjectID('...')},
{$lookup: {
from: 'collectionTwo',
localField: 'groups.things.foreignId',
foreignField: '_id',
as: 'aggregatedThings'
}},
])
So I want to set localField to a path, that matches every object in groups. Something like this, where $ is a placeholder for every key:
collectionOne.aggregate([
{$match: {_id, ObjectID('...')},
{$lookup: {
from: 'collectionTwo',
localField: 'groups.$.things.foreignId',
foreignField: '_id',
as: 'aggregatedThings'
}},
])
I hope my problem is clear.
Appreciate any help. :)
I found a solution to this.
collectionOne.aggregate([
{$match: {_id, ObjectID('...')},
{ '$addFields': {
'groupsArray': { $objectToArray: '$groups' }
}},
{$lookup: {
from: 'collectionTwo',
localField: 'groupsArray.v.things.foreignId',
foreignField: '_id',
as: 'aggregatedThings'
}},
])
Converting the object to an Array using $objectToArray does the trick for me.

MongoDB $lookup multiple localFields from one document

I've got Adresses model:
{
user1: ObjectId(),
user2: ObjectId()
}
Each user field is reference to User model.
Is it possible to perform one lookup which will propagate data?
You can just put multiple references as following:
collection.aggregate([
{
$lookup: {
from: "whereyouwant",
localField: "localfield",
foreignField: "foreignfield",
as: "name1"
}
},
{
$lookup: {
from: "whereyouwant2",
localField: "localfield2",
foreignField: "foreignfield2",
as: "name2"
}
},... rest of code