MongoDB query using intersection of 2 lists - mongodb

I'm working on a project where we use mongodb 4.4 as our database. The problem is I have to make a query that is too complicated using mongo query language.
That's an exemple of the data in the database:
{
"neededQuantity": 100,
"auth": {
"groups": ["group-1"]
},
"createTime": "2022-02-03T14:17:25.809704600Z",
},
{
"neededQuantity": 120,
"auth": {
"groups": ["group-3"]
},
"createTime": "2022-02-02T14:17:25.809704600Z",
},
{
"neededQuantity": 150,
"auth": {
"groups": ["group-2","group-1"]
},
"createTime": "2022-02-01T14:17:25.809704600Z",
}
The query has to find the documents that have at least 1 element of the list auth.groups in common with an another list that is given as input.
If the input list is ["group-1"], the query result should be:
{
"neededQuantity": 100,
"auth": {
"groups": ["group-1"]
},
"createTime": "2022-02-03T14:17:25.809704600Z",
},
{
"neededQuantity": 150,
"auth": {
"groups": ["group-2","group-1"]
},
"createTime": "2022-02-01T14:17:25.809704600Z",
}
How can I do it?
Thank you very much in advance.

you can do it with $in
db.collection.find({
"auth.groups": {$in: ["group-1"]}
})
playground
more detail about $in here

Related

Populate Search MongoDB Objects

Can you please tell me how to search for a nested object (only _id appears in it and is expanded via .populate() )?
I need to search by title and album.title, how can I do this?
async getAll(searchTerm?: string) {
let options = {}
if (searchTerm) {
options = {
$or: [
{
title: new RegExp(searchTerm.trim(), 'gi'),
},
],
}
}
return this.TrackModel.find(options)
.select('-updatedAt -__v')
.sort({ createdAt: 'desc' })
.populate('album author')
.exec()
}
image of JSON below
[
{
"_id": "638cec330c055283f3eeb227",
"poster": "/uploads/tracks/Coolio/Coolio-cover.jpg",
"title": "Gangsta's Paradise",
"slug": "gangstasparadise",
"duration": 240,
"countPlays": 7269322,
"trackUrl": "/uploads/tracks/Coolio/Coolio - Gangstas Paradise.mp3",
"album": [
{
"_id": "638ceb960c055283f3eeb225",
"title": "Gangsta's Paradise",
"slug": "gangstasparadise",
"poster": "/uploads/tracks/Coolio/Coolio-cover.jpg",
"author": [
"638ce9f50c055283f3eeb223"
],
"createdAt": "2022-12-04T18:48:54.306Z",
"updatedAt": "2022-12-04T18:48:54.306Z",
"_v": 0
}
]
}
]
I tried to search using $or, but I ran into a problem that at the time of the search, only _id is stored in the album array.

MongoDB -Query documents where nested array fields is equal to some value

I have a JSON object:
{
"ownershipSheetB": {
"lrUnitShares": [{
"description": "blabla1",
"lrOwners": [{
"lrOwnerId": 35780527,
"name": "somename1",
"address": "someadress1",
"taxNumber": "12345678910"
}
],
"lrUnitShareId": 29181970,
"subSharesAndEntries": [],
"orderNumber": "1"
}, {
"description": "blabla2",
"lrOwners": [{
"lrOwnerId": 35780528,
"name": "somename2",
"address": "someadress2",
"taxNumber": "12345678911"
}
],
"lrUnitShareId": 29181971,
"subSharesAndEntries": [],
"orderNumber": "2"
}
],
"lrEntries": []
}
}
I would like to query all documents that have taxNumber field equal to some string (say "12345678911" from the example above).
I have tried this query:
{"ownershipSheetB.lrUnitShares": { "lrOwners": {"taxNumber": "12345678910"}}}
but it returns no documents.
Solution 1: With dot notation
db.collection.find({
"ownershipSheetB.lrUnitShares.lrOwners.taxNumber": "12345678910"
})
Demo Solution 1 # Mongo Playground
Solution 2: With $elemMatch
db.collection.find({
"ownershipSheetB.lrUnitShares": {
$elemMatch: {
"lrOwners": {
$elemMatch: {
"taxNumber": "12345678910"
}
}
}
}
})
Demo Solution 2 # Mongo Playground

How to use aggregation to pull information from a nested array on objects in mongoDB

I am trying to get the hang of the aggregation in mongoDB, I am new at this and I think I kinda got lost.
I have a collection of users, each user has an array of social networks, and each item in this array is an object.
How do I get value only from a given social network/s object/s.
{
"user":{
"_id": "d10430c8-e59",
"username": "John",
"password": "f7wei93",
"location": "UK",
"gender": "Male",
"age": 26,
"socials": [
{
"type": "instagram",
"maleFollowers": 23000,
"femaleFollowers": 65000,
"posts": 5400,
"avgFollowerAge": 22
},
{
"type": "facebook",
"maleFollowers": 4000,
"femaleFollowers": 6700,
"posts": 330,
"avgFollowerAge": 25
},
{
"type": "snapchat",
"maleFollowers": 873,
"femaleFollowers": 1200,
"posts": 1200,
"avgFollowerAge": 21
},
]
}
}
I want to get the totalFollowersCount ( maleFollowers + femaleFollowers)
for each social network type that is given in an array.
for example ["instagram", "snapchat"] will only give me the totalFollowersCount for this two specific networks.
I started playing around with aggregation but didn't figure it out all the way.
First, we need to flatten the socials array. Then, we group by socials type + 'user' fields and sum( maleFollowers + femaleFollowers).
With $match operator, we filter desired social networks.
db.users.aggregate([
{
$unwind: "$user.socials"
},
{
$group: {
_id: {
user: "$user._id",
type: "$user.socials.type"
},
"totalFollowersCount": {
$sum: {
$add: [
"$user.socials.femaleFollowers",
"$user.socials.maleFollowers"
]
}
}
}
},
{
$match: {
"_id.type": {
$in: [
"instagram",
"snapchat"
]
}
}
}
])
MongoPlayground

Move data from inside nested array

I have inserted multiple documents in my Mongo database incorrectly. I have accidentally nested the data inside another data object:
{
"_id": "5cdfda8ddc5cf00031fd3949",
"payload": {
"timestamp": "2019-05-18T10:12:29.896Z",
"data": {
"data": {
"name": 10,
"age": 10,
}
}
},
"__v": 0
}
I would like the document to not have the extra data object. So I would like it to look like this:
{
"_id": "5cdfda8ddc5cf00031fd3949",
"payload": {
"timestamp": "2019-05-18T10:12:29.896Z",
"data": {
"name": 10,
"age": 10,
}
},
"__v": 0
}
Is there a way in Mongo for me to update all the documents that have 2 data objects to just have one like shown above?
Alas, you cannot do this with one database request. You have to loop over all documents programmatically, set the new data and update them in the database.
You could use the aggregation framework, which won't let you update in place, but you could use the $out operator to write the results to a new collection, if that's an option.
db.collection.aggregate([
{
$project: {
__v : 1,
"payload.timestamp" : 1,
"payload.data" : "$payload.data.data"
},
},
{
"$out": "newCollection"
}
])
Or if you have a mixture of docs with correct format and docs with incorrect format, you can use the $cond operator to determine the correct output:
db.collection.aggregate([
{
$project: {
__v : 1,
"payload.timestamp" : 1,
"payload.data" : {
$cond: [
{ $ne : [ "$payload.data.data", undefined]},
"$payload.data.data",
"$payload.data"
]}
}
},
{
"$out": "newCollection"
}
])

Mongoose aggregate match returns empty array

I'm working with mongodb aggregations using mongoose and a I'm doubt what am I doing wrong in my application.
Here is my document:
{
"_id": "5bf6fe505ca52c2088c39a45",
"loc": {
"type": "Point",
"coordinates": [
-43.......,
-19......
]
},
"name": "......",
"friendlyName": "....",
"responsibleName": "....",
"countryIdentification": "0000000000",
"categories": [
"5bf43af0f9b41a21e03ef1f9"
]
"created_at": "2018-11-22T19:06:56.912Z",
"__v": 0
}
At the context of my application I need to search documents by GeoJSON, and I execute this search using geoNear. Ok it works fine! But moreover I need to "match" or "filter" specific "categories" in the document. I think it's possible using $match but certainly I'm doing the things wrong. Here is the code:
CompanyModel.aggregate(
[
{
"$geoNear": {
"near": {
"type": "Point",
"coordinates": [pageOptions.loc.lng, pageOptions.loc.lat]
},
"distanceField": "distance",
"spherical": true,
"maxDistance": pageOptions.distance
}
},
{
"$match": {
categories: { "$in": [pageOptions.category] }
}
}
]
).then(data => {
resolve({ statusCode: 200, data: data });
}).catch(err => {
console.log(err);
reject({ statusCode: 500, error: "Error getting documents", err: err });
})
pageOptions:
var pageOptions = {
loc: {
lat: parseFloat(req.query.lat),
lng: parseFloat(req.query.lng)
},
distance: parseInt(req.query.distance) || 10000,
category: req.params.category || ""
}
If I remove $match I get all the documents by location, but I need to filter specific categories... I don't believe that I need to filter it manually, I believe it can be possible with aggregation functions...
So anyone can help me with this mongoose implementation?
Thanks for all help
In MongoDB you need to make sure that data type in your document matches the type in your query. In this case you have a string stored in the database and you're trying to use ObjectId to build the $match stage. To fix that you can use valueOf() operator on pageOptions.category, try:
{
"$match": {
categories: { "$in": [pageOptions.category.valueOf()] }
}
}