I have two collections
A collection to save following users
A collection for user stories
I want to see only the stories of the users I have followed
This is an example of my database
db = {
"follow": [
{
"_id": 1,
"start": "user1",
"end": "user2",
},
{
"_id": 2,
"start": "user2",
"end": "user3",
}
],
"story": [
{
"_id": 1,
"owner_id": "user2",
"updated_at": 1638090000,
"deleted_at": null
},
{
"_id": 2,
"owner_id": "user3",
"updated_at": 1638080000,
"deleted_at": null
}
]
}
I want such a query. Of course, this is wrong:
db.story.aggregate([
{
"$match": {
"deleted_at": null,
"updated_at": {
$gte: 1638081000
},
"owner_id": {
$in: [
db.follow.find({"start": "user1"})
]
}
}
}
])
Note that I want all of this to be done in one query
query in mongo playground : https://mongoplayground.net/p/ysRUDW4hRzh
You should use $lookup here
db.follow.aggregate([
{
"$match": {
"start": "user2"
}
},
{
$lookup: {
from: "story",
localField: "end",
foreignField: "owner_id",
pipeline: [],
as: "stories",
}
},
])
this query lookups story database where localField (end in this case) equals foreignField (owner_id in this case) then puts on a stories field
result:
https://mongoplayground.net/p/0M6YxYWAQ2n
Related
What I have is a collection of documents in MongoDB that have the structure something like this
[
{
"userid": "user1",
"addresses": [
{
"type": "abc",
"street": "xyz"
},
{
"type": "def",
"street": "www"
},
{
"type": "hhh",
"street": "mmm"
},
]
},
{
"userid": "user2",
"addresses": [
{
"type": "abc",
"street": "ccc"
},
{
"type": "def",
"street": "zzz"
},
{
"type": "hhh",
"street": "yyy"
},
]
}
]
If I can give the "type" and "userid", how can I get the result as
[
{
"userid": "user2",
"type": "abc",
"street": "ccc",
}
]
It would also be great even if I can get the "street" only as the result. The only constraint is I need to get it in the root element itself and not inside an array
Something like this:
db.collection.aggregate([
{
$match: {
userid: "user1" , "address.type":"abc"
}
},
{
$project: {
userid: 1,
address: {
$filter: {
input: "$addresses",
as: "a",
cond: {
$eq: [
"$$a.type",
"abc"
]
}
}
}
}
},
{
$unwind: "$address"
},
{
$project: {
userid: 1,
street: "$address.street",
_id: 0
}
}
])
explained:
Filter only documents with the userid & addresess.type you need
Project/Filter only the addresses elements with the needed type
unwind the address array
project only the needed elements as requested
For best results create index on the { userid:1 } field or compound index on { userid:1 , address.type:1 } fields
playground
You should be able to use unwind, match and project as shown below:
db.collection.aggregate([
{
"$unwind": "$addresses"
},
{
"$match": {
"addresses.type": "abc",
"userid": "user1"
}
},
{
"$project": {
"_id": 0,
"street": "$addresses.street"
}
}
])
You can also duplicate the match step as the first step to reduce the number of documents to unwind.
Here is the playground link.
There is a similar question/answer here.
This is a sample collection in which I want to update a user's posts. In fact, I want to operate a command similar to $push and $pop so that I can remove or add the userId from the likes array inside the posts array, this seems fairly simple but the catch is that I want to update the likes of a particular post matched by _id field of objects within posts array.
[
{
"_id": {
"$oid": "61375acc1c7d0a1a6e6005f0"
},
"fullName": "user1",
"email": "user1#gmail.com",
"password": "$2b$10$Yrs5H3mYrM8xLwWlek3K7uAs.EOLsXggj6wV7oSflPlPjo1ZkFem6",
"avatar": "https://avatars.dicebear.com/api/human/vishnu#gmail.com.svg",
"posts": [
{
"postContent": "sample 1",
"medias": [
"files/78560be22a25988c38ddafa0be7558f73713607a.jpeg"
],
"createdAt": {
"$date": "2021-09-07T12:40:54.930Z"
},
"userId": {
"$oid": "61375acc1c7d0a1a6e6005f0"
},
"authorName": "user1",
"avatar": "https://avatars.dicebear.com/api/human/vishnu#gmail.com.svg",
"likes": [],
"comments": [],
"_id": {
"$oid": "61375dd61c7d0a1a6e6005f3"
}
},
{
"postContent": "sample 2",
"medias": [
"files/5af7e5086e8dfb8af6c8e7bac3f2430a78d80ac1.jpeg",
"files/c01ed66cef55c876c8e7800aa5c820b9aeee7267.jpeg"
],
"createdAt": {
"$date": "2021-09-07T12:42:01.142Z"
},
"userId": {
"$oid": "61375acc1c7d0a1a6e6005f0"
},
"authorName": "user 2",
"avatar": "https://avatars.dicebear.com/api/human/user2#gmail.com.svg",
"likes": [],
"comments": [],
"_id": {
"$oid": "61375e191c7d0a1a6e6005f4"
}
}
],
"friendRequests": []
}
]
i.e, once a query is executed the likes array of the particular post (matched by _id) has to be updated with the userId (both userId and postId will be input in this case)
eg:
document.posts.likes = [61375acc1c7d0a1a6e6005f0, 61375acc1c7d0a1aasdfasgre3]
There is no straight way to do this, you can try update with aggregation pipeline starting from MongoDB 4.2,
$map to iterate look of posts array
$cond to check if post id match then go to update part otherwise return same object
$cond to check if user id in likes array then go to remove part otehrwise add id in likes
$filter to iterate loop of likes array and remove user id
$concatArrays add user id in likes array
$mergeObjects to merge current object with updated likes array field
let postId = { "$oid": "61375e191c7d0a1a6e6005f4" };
let userId = "61375dd61c7d0a1a6e6005f1";
db.collection.updateOne(
{ "posts._id": postId },
[{
"$set": {
"posts": {
$map: {
input: "$posts",
as: "p",
in: {
$cond: [
{ $eq: ["$$p._id", postId ] },
{
$mergeObjects: [
"$$p",
{
"likes": {
"$cond": [
{ $in: [userId, "$$p.likes"] },
{
$filter: {
input: "$$p.likes",
cond: { $ne: ["$$this", userId] }
}
},
{
"$concatArrays": ["$$p.likes", [userId]]
}
]
}
}
]
},
"$$p"
]
}
}
}
}
}]
)
Playground
i want to compare collection with array in aggregate result
i have following two collection.
chat collection
chat.tags is a array value in reference key come from the tags collection.
"chat": [
{
"id": "test1",
"tags": [
"AAA",
"BBB",
"CCC",
"AAA"
]
},
{
"id": "test2",
"tags": [
"AAA",
"BBB",
"CCC"
]
}
]
tag collection
"tag": [
{
"id": "1234",
"key": "AAA",
"name": "a"
},
{
"id": "1235",
"key": "BBB",
"name": "b"
},
{
"id": "1236",
"key": "CCC",
"name": "c"
},
{
"id": "1237",
"key": "DDD",
"name": "d"
},
]
i want to result that id is "test1" and unique tags in chat collection.
i want to following result using with mongo aggregate.
Is it possible with from, let, pipeline when using lookup?
[
{
"chat": [
{
"id": "test1",
"setTags": [
"AAA",
"BBB",
"CCC"
]
}
],
"tag": [
{
"id": "1234",
"key": "AAA",
"name": "a"
},
{
"id": "1235",
"key": "BBB",
"name": "b"
},
{
"id": "1236",
"key": "CCC",
"name": "c"
}
]
}
]
please help me.
This can be achieved with a simple $lookup, like so:
db.chat.aggregate([
{
$match: {
id: "test1"
}
},
{
$lookup: {
from: "tag",
localField: "tags",
foreignField: "key",
as: "tagDocs"
}
},
{
$project: {
chat: [
{
id: "$id",
setTags: "$tags"
}
],
tag: "$tagDocs"
}
}
])
Mongo Playground
I didn't fully understand what the output structure you want is but it can easily be changed via a different $project stage.
--- EDIT ---
With Mongo's v3.6 $lookup syntax the pipeline remains the same, just the $lookup stage changes:
{
$lookup: {
from: "tag",
let: {
tagKeys: "$tags"
},
pipeline: [
{
$match: {
$expr: {
$in: [
"$key",
"$$tagKeys"
]
}
}
}
],
as: "tagDocs"
}
},
Mongo Playground
My document have this structure
_id: "adklkj389723jk23KLJjl2LU92kJO387"
"impressions": [{
"_id": ObjectId("5b74799535f2722494075981"),
"country": "GB",
"impression_count": 22,
"_campaignid": ObjectId("5b72d78847db422040ee60cf"),
"date": ISODate("2018-08-15T19:00:00Z")
},
{
"_id": ObjectId("5b74799d35f2722494075982"),
"country": "GB",
"impression_count": 22,
"_campaignid": ObjectId("5b72d7bf47db422040ee60d1"),
"date": ISODate("2018-08-15T19:00:00Z")
},
{
"_id": ObjectId("5b7479a735f2722494075983"),
"country": "GB",
"impression_count": 20,
"_campaignid": ObjectId("5b72d79e47db422040ee60d0"),
"date": ISODate("2018-08-15T19:00:00Z")
}
]
What i want to do
I want to group impressions with dates on which they are created where i am saving date as string in db to do this I am using this query
db.advertisers.aggregate([{
$group: {
_id: "$impressions.date",
count: {
$sum: "$impressions.impression_count"
}
}
}]).pretty()
Result
This query is giving me the result like so what am i doing wrong ?
{
"_id": [
ISODate("2018-08-15T19:00:00Z"),
ISODate("2018-08-15T19:00:00Z"),
ISODate("2018-08-15T19:00:00Z")
],
"count": 1
}
Since you are dealing with an array you might want to unwind the impressions:
db.collection.aggregate([
{
"$unwind": "$impressions"
},
{
$group: {
_id: "$impressions.date",
count: {
$sum: "$impressions.impression_count"
},
}
}
])
This would give you:
[
{
"_id": ISODate("2018-08-15T19:00:00Z"),
"count": 64
}
]
You can see this here.
I have a DB structure as follows:
{
"Title": "AAA",
"Photos": ["/aaa/aaa.png"],
"Loc": "XXX",
"Emp": "SSS",
"Rate": [{
"Rating": 2,
"RateID": "12345654654",
"RatedDate": new Date()
}],
"Fav": [{
"FavValue": 2,
"FavID": "1111",
"FavDate": new Date()
}]
}
Here, I want to fetch all the details by default. But from array, i need to get the object that matches the ID.
In "Rate" array it needs to match "RateID" and in "Fav" array it need to match "FavID".
Both "Rate" and "Fav" wont contains objects always.
I have tried foll mongoose aggregate:
ss.aggregate([
{ $unwind: "$Rate" },
{
$group: {
"_id": '$_id',
"Title": { "$first": "$Title" },
"Loc": { "$first": "$Loc" },
"Emp": { "$first": "$Emp" },
"Photos": { "$first": "$Photos" },
"Rate": { $max: { $cond: [ { $eq: [ "$Rate.RateID", new ObjectId(id) ] }, '$Rate.Rating', null ] } },
"Fav": { $max: { $cond : [ { $eq : [{ "$size": "$Fav" }, 0]}, null, { $cond: [ { $eq: [ "$Fav.FavID", new ObjectId(id) ] }, '$Fav.FavValue', null ] } ]} }
}
}
], function (err, AvgResult) {
res.json({"result": AvgResult});
});
For "Rate", if the array is empty it returns empty result as {}
For "Fav", it returns null always if the array is empty or if it contains object
If I send the ID as '12345654654', the result should be like
{
"Title": "AAA",
"Photos": ["/aaa/aaa.png"],
"Loc": "XXX",
"Emp": "SSS",
"Rate": 2,
"Fav": null
}
If the ID is "1111", the result should be
{
"Title": "AAA",
"Photos": ["/aaa/aaa.png"],
"Loc": "XXX",
"Emp": "SSS",
"Rate": null,
"Fav": 2
}
If "Fav" is empty array in DB like "Fav": [] and ID - is "12345654654", then the result should be as follows
{
"Title": "AAA",
"Photos": ["/aaa/aaa.png"],
"Loc": "XXX",
"Emp": "SSS",
"Rate": 2,
"Fav": null
}
can any one help to get the expected result in all the above scenario..