how to find unique values from array of object in mongoDB - database

i have following bson data in mongoDB
{name : "c1"
arr : [
{
partyName : "p1",
poNumber : "789",
},
{
partyName : "p1",
poNumber : "700",
},
{
partyName : "p3",
poNumber : "889",
}
]
},
{name : "c2"
arr : [
{
partyName : "p1",
poNumber : "789",
},
{
partyName : "p2",
poNumber : "700",
},
{
partyName : "p3",
poNumber : "889",
}
]
}
i want all unique values of partyName of name: "c1" object like [p1,p3]. i tried this
const unique = await User.distinct({name :"c1","createPurchaseOrder.partyName"})
(note :- User is my schema name )
but it gives error, i tried to search on web but cant find solution please help me with this

One option is using $reduce:
db.collection.aggregate([
{$match: {name: "c1"}},
{$project: {
res: {
$reduce: {
input: "$arr",
initialValue: [],
in: {$setUnion: ["$$value", ["$$this.partyName"]]}
}
}
}
}
])
See how it works on the playground example

Query1
match for the document with name=c1
path to take the array with the partyName and union with the empty array to remove the duplicates
union => order can be lost in patyNames
Playmongo
aggregate(
[{"$match": {"name": {"$eq": "c1"}}},
{"$project":
{"_id": 0, "parties-unique": {"$setUnion": ["$arr.partyName", []]}}}])
Query2
the above is fast and simple but loses the order of the names
if you want to keep the original order, you can use this instead
reduce and add on array only if element doesn't already exists
Playmongo
aggregate(
[{"$match": {"name": {"$eq": "c1"}}},
{"$set":
{"parties-unique":
{"$reduce":
{"input": "$arr.partyName",
"initialValue": [],
"in":
{"$cond":
[{"$in": ["$$this", "$$value"]}, "$$value",
{"$concatArrays": ["$$value", ["$$this"]]}]}}}}}])

Related

how to get object from array by value inside desired object by mongoose

i have following bson data in mongoDB
{
[
{
partyName : "p1",
poNumber : "789",
},
{
partyName : "p2",
poNumber : "700",
},
{
partyName : "p3",
poNumber : "889",
}
]
}
i want object from partyName for example if partyName is p1 then i want this
{
partyName : "p1",
poNumber : "789",
}
i searched on the internet but not find relative result, all i found that query.elemMatch may help but i don't know how to use it please help me with the solution ( i want to use only mongoose )
await EntityName.findOne(
{ mainEntityName: { $elemMatch: { partyName: "p1" } } })
You can try this. Fill the EntityName and mainEntityName parts as your schema's names.
! Instead of "p1", add your parameter came from query.
To reach all elements which matched with your filter ; use find()
await EntityName.find(
{ mainEntityName: { $elemMatch: { partyName: "p1" } } })

how to get objects from array by value inside desired object by mongoose

I have following bson data in mongoDB
{
name : "company 1",
createPurchaseOrder :[
{
partyName : "p1",
poNumber : "789",
},
{
partyName : "p2",
poNumber : "700",
},
{
partyName : "p3",
poNumber : "889",
},
{
partyName : "p1",
poNumber : "800",
},
{
partyName : "p1",
poNumber : "200",
},
]
}
I want objects from partyName for example if partyName is p1 then I want this
[
{
partyName: 'p1',
poNumber: '789',
},
{
partyName: 'p1',
poNumber: '800',
},
{
partyName: 'p1',
poNumber: '200',
},
];
I tried this
const user1 = await User.findOne({name : "company 1"},{createPurchaseOrder:{$elemMatch:{partyName:"p1"}}})
its gives me only first matched object, then I tried this
const user1 = await User.find({name : "company 1"},{createPurchaseOrder:{$elemMatch:{"partyName.$":"p1"}}})
it returned an empty array. please help me with this I want solution which gives me all objects which have matched value
You need to use the aggregation pipeline for this, the find operator is very limited with what structure transformation it can do and for example this use case can't be achieved using it.
Just use $filter instead:
db.collection.aggregate([
{
$match: {
name: "company 1"
}
},
{
$addFields: {
createPurchaseOrder: {
$filter: {
input: {
$ifNull: [
"$createPurchaseOrder",
[]
]
},
cond: {
$eq: [
"$$this.partyName",
"p1"
]
}
}
}
}
},
{
$unwind: "$createPurchaseOrder"
},
{
$replaceRoot: {
newRoot: "$createPurchaseOrder"
}
}
])
Mongo Playground

How to merge an array field in multiple documents into a single output array in MongoDB and mongoexport to csv

I have a MongoDB collection, Groups. Each group has an array of members, referenced by the member's unique id. A user can be a member of many groups.
Group data looks like this:
{ _id: 1, members: ['1', '3', '5'], status: 'active' }
{ _id: 2, members: ['4', '1', '10', '11'], status: 'inactive' }
{ _id: 3, members: ['1', '2', '9'], status: 'active' }
I'm trying to extract all members of active groups as a single array of member ids, without duplication. I want to export them to a csv file using mongoexport.
I can export the ids of the relevant projects and their member lists:
mongoexport -h localhost:3001 --db mydbname --collection groups --type=csv --fields _id,members --query '{"status": "active"}' --out mongotestoutput.txt
But I can't figure out how to merge the member lists into a single array. I've been looking at Aggregation but I'm just getting lost among all the different options, I can't see which one would do what I need. Very grateful for any help.
Use aggregation with $unwind and then $out to create a new collection that looks like you need. Then export this new collection to CSV file.
db.test1.insertMany([
{ _id: 1, members: ['1', '3', '5'], status: 'active' },
{ _id: 2, members: ['4', '1', '10', '11'], status: 'inactive' },
{ _id: 3, members: ['9'], status: 'active' }
])
{_id:0} here and below is used to suppress _id field
db.test1.aggregate([
{$unwind: "$members"},
{$project:{_id:0}},
{$out:"test2"}
])
db.test2.find({},{_id:0})
{ "members" : "1", "status" : "active" }
{ "members" : "3", "status" : "active" }
{ "members" : "5", "status" : "active" }
{ "members" : "4", "status" : "inactive" }
{ "members" : "1", "status" : "inactive" }
{ "members" : "10", "status" : "inactive" }
{ "members" : "11", "status" : "inactive" }
{ "members" : "9", "status" : "active" }
Or if you need to get members by status in the array - add another $group, $addToSet stage:
db.test1.aggregate([
{$unwind: "$members"},
{$project:{_id:0}},
{ "$group": { "_id": "$status", members:{$addToSet:"$members"} } },
{$out:"test3"}
])
db.test3.find()
{ "_id" : "inactive", "members" : [ "4", "1", "10", "11" ] }
{ "_id" : "active", "members" : [ "1", "3", "5", "9" ] }
See MongoPlayground
This question shows two ways to get the result I'm looking for. The accepted answer uses push, reduce and setUnion. The newer answer is simpler, using unwind and addToSet. Both work for me but I'm going with the simpler version:
db.collection.aggregate([
{ $match: { "status": "active" },
{ $unwind: "$members"},
{ $group:{
_id: 0,
selectedMembers: { $addToSet: '$members' }
}}
])
I'm extracting the array I want from the JSON object returned by this expression.

How to fetch places based on geoNear 2dsphere index and category array using MongoDB?

This is a sample document from a mongoDB collection:-
{
"place_id" : "57222c6f498e78e3bfe0a575",
"title_AR" : "University Institute Hall",
"title_EN" : "University Institute Hall",
"description_AR" : "",
"description_EN" : "",
"best_photo" : "https://igx.4sqi.net/img/general/250x250/8862268_8oi3vr81Zm3ucytWjoSyvWXXS-7BUpNxKgyJvj0Lusc.jpg",
"city_AR" : "Kolkata",
"city_EN" : "Kolkata",
"state_AR" : "West Bengal",
"state_EN" : "West Bengal",
"country" : "IN",
"postal_code_AR" : "700073",
"postal_code_EN" : "700073",
"location_AR" : "7, Bankim Chatterjee St, Kolkata 700073, West Bengal, India",
"location_EN" : "7, Bankim Chatterjee St, Kolkata 700073, West Bengal, India",
"latitude" : 22.5744745110906,
"longitude" : 88.3630291046031,
"loc" : {
"type" : "Point",
"coordinates" : [
88.3630291046031,
22.5744745110906
]
},
"website" : "",
"email" : "",
"contact_number_AR" : "+913322416214",
"contact_number_EN" : "+913322416214",
"ratings_AR" : "",
"ratings_EN" : "",
"no_of_comments_AR" : 0,
"no_of_comments_EN" : 0,
"categories" : "4d4b7104d754a06370d81259,5032792091d4c4b30a586d5c,4d4b7104d754a06370d81259,5032792091d4c4b30a586d5c",
"category_array" : [
"4d4b7104d754a06370d81259",
"5032792091d4c4b30a586d5c",
"4d4b7104d754a06370d81259",
"5032792091d4c4b30a586d5c"
],
"created_date" : "2018-05-31 16:39:33",
"modified_date" : "2018-05-31 16:39:33",
"photo_saved" : 0,
"tip_saved" : 0,
"updated_at" : ISODate("2018-05-31T11:09:33.000Z"),
"created_at" : ISODate("2018-05-31T11:09:33.000Z")
}
The category array contains all the category ids under which the place falls.
"category_array" : [
"4d4b7104d754a06370d81259",
"5032792091d4c4b30a586d5c",
"4d4b7104d754a06370d81259",
"5032792091d4c4b30a586d5c"
]
I want to fetch the places based on the location and category. Here is my script:-
db.runCommand(
{
geoNear: "foursquare_places",
near: { type: "Point", coordinates: [ 88.363892, 22.572645 ] },
spherical: true,
query: { category_array: { $all: ["5032792091d4c4b30a586d5c"] }},
maxDistance: 500
}
)
Now here is the issue. According to the Mongo document:-
To makes an exact array match, including the order of the elements:-
db.inventory.find( { tags: ["red", "blank"] } )
To find an array that contains both the elements "red" and "blank", without regard to order or other elements in the array:-
db.inventory.find( { tags: { $all: ["red", "blank"] } } )
The following example queries for all documents where tags is an array that contains the string "red" as one of its elements
db.inventory.find( { tags: "red" } )
What will be the query to fetch all the records whose category_array contains either or all of the elements of the following array?
findArray = ['4d4b7104d754a06370d81259', '4d4b7104d754a06370d81259',
'5032792091d4c4b30a586d5c']
"either or all" makes little sense to me. Assuming it is "at least one of", you need to use $in:
query: { category_array: { $in: [
'4d4b7104d754a06370d81259',
'4d4b7104d754a06370d81259',
'5032792091d4c4b30a586d5c'
] } }
Will return all documents where category_array has at least one of 3 strings.

MongoDb projection on array of objects, Get matched object only [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 4 years ago.
I have mongo document like this
{
"_id": "5b14679e592baa493e0bc208",
"productCode": "ABC",
"corridors": [
{
"countryNameEn": "Sweden",
"countryNameFr": "Suède",
"countryCode": "SE",
"currencyNameEn": "Swedish Krona",
"currencyNameFr": "Couronne suédoise",
"currencyCode": "SEK",
"corridorLimit": "abc"
},
{
"countryNameEn": "USA",
"countryNameFr": "Suède",
"countryCode": "US",
"currencyNameEn": "USA",
"currencyNameFr": "Couronne suédoise",
"currencyCode": "USD",
"corridorLimit": "abc"
}
]
},
{
"_id": "5b14679e592baa493e0bc208",
"productCode": "XYZ",
"corridors": [
{
"countryNameEn": "Sweden",
"countryNameFr": "Suède",
"countryCode": "SE",
"currencyNameEn": "Swedish Krona",
"currencyNameFr": "Couronne suédoise",
"currencyCode": "SEK",
"corridorLimit": "abc"
},
{
"countryNameEn": "USA",
"countryNameFr": "Suède",
"countryCode": "US",
"currencyNameEn": "USA",
"currencyNameFr": "Couronne suédoise",
"currencyCode": "USD",
"corridorLimit": "abc"
}
]
}
I want to find document whose productCode is ABC and currencyCode is USD in corridors array. How can I return only the matching object from corridors array like only only object that has USD currencyCode should come in result and not all array.
I tried running this query { productCode: 'ABC', corridors: { $elemMatch: { currencyCode: "USD"}}}. But it gives me the whole array and not the only matched element.
I don't think you can use $elemMatch in $project. Check this
Try the following query:
db.collection.aggregate([
{
$match : {"productCode" : "ABC"}
},
{
$unwind : "$corridors"
},
{
$match : { "corridors.currencyCode" : "USD"}
},
{
$group : {
_id : "$productCode",
corridors : {$addToSet : "$corridors"}
}
}]);
Outputs:
{
"_id" : "ABC",
"corridors" : [
{
"countryNameEn" : "USA",
"countryNameFr" : "Suède",
"countryCode" : "US",
"currencyNameEn" : "USA",
"currencyNameFr" : "Couronne suédoise",
"currencyCode" : "USD",
"corridorLimit" : "abc"
}
]
}
In the result you'll have _id instead of productCode. If you still want productCode, you can just include $project in the end.
Hope this helps!

Resources