Reshaping Documents in $project Stages - node.js

For our collection which looks like this:
> db.companies.find().limit(1).pretty() {
"_id": ObjectId("52cdef7c4bab8bd675297d8b"),
"name": "AdventNet",
"permalink": "abc3",
"crunchbase_url": "http://www.crunchbase.com/company/adventnet",
"homepage_url": "http://adventnet.com",
"blog_url": "",
"blog_feed_url": "",
"twitter_username": "manageengine",
"category_code": "enterprise",
"number_of_employees": 600,
"founded_year": 1996,
"deadpooled_year": 2,
"tag_list": "",
"alias_list": "Zoho ManageEngine ",
"email_address": "pr#adventnet.com",
"phone_number": "925-924-9500",
"description": "Server Management Software",
"created_at": ISODate("2007-05-25T19:24:22Z"),
"updated_at": "Wed Oct 31 18:26:09 UTC 2012",
"overview": "<p>AdventNet is now <a href=\"/company/zoho-manageengine\"
title=\"Zoho ManageEngine\" rel=\"nofollow\">Zoho ManageEngine</a>.</p>\n\n<p>F
ounded in 1996, AdventNet has served a diverse range of enterprise IT, networkin
g and telecom customers.</p>\n\n<p>AdventNet supplies server and network managem
ent software.</p>",
"image": {
"available_sizes": [
[
[
150,
55
],
"assets/images/resized/0001/9732/19732v1-max-150
x150.png"
],
[
[
150,
55
],
"assets/images/resized/0001/9732/19732v1-max-250
x250.png"
],
[
[
150,
55
],
"assets/images/resized/0001/9732/19732v1-max-450
x450.png"
]
]
},
"products": [],
"relationships": [{
"is_past": true,
"title": "CEO and Co-Founder",
"person": {
"first_name": "Sridhar",
"last_name": "Vembu",
"permalink": "sridhar-vembu"
}
}, {
"is_past": true,
"title": "VP of Business Dev",
"person": {
"first_name": "Neil",
"last_name": "Butani",
"permalink": "neil-butani"
}
}, {
"is_past": true,
"title": "Usabiliy Engineer",
"person": {
"first_name": "Bharath",
"last_name": "Balasubramanian",
"permalink": "bharath-balasibramanian"
}
}, {
"is_past": true,
"title": "Director of Engineering",
"person": {
"first_name": "Rajendran",
"last_name": "Dandapani",
"permalink": "rajendran-dandapani"
}
}, {
"is_past": true,
"title": "Market Analyst",
"person": {
"first_name": "Aravind",
"last_name": "Natarajan",
"permalink": "aravind-natarajan"
}
}, {
"is_past": true,
"title": "Director of Product Management",
"person": {
"first_name": "Hyther",
"last_name": "Nizam",
"permalink": "hyther-nizam"
}
}, {
"is_past": true,
"title": "Western Regional OEM Sales Manager",
"person": {
"first_name": "Ian",
"last_name": "Wenig",
"permalink": "ian-wenig"
}
}],
"competitions": [],
"providerships": [{
"title": "DHFH",
"is_past": true,
"provider": {
"name": "A Small Orange",
"permalink": "a-small-orange"
}
}],
"total_money_raised": "$0",
"funding_rounds": [],
"investments": [],
"acquisition": null,
"acquisitions": [],
"offices": [{
"description": "Headquarters",
"address1": "4900 Hopyard Rd.",
"address2": "Suite 310",
"zip_code": "94588",
"city": "Pleasanton",
"state_code": "CA",
"country_code": "USA",
"latitude": 37.692934,
"longitude": -121.904945
}],
"milestones": [],
"video_embeds": [],
"screenshots": [{
"available_sizes": [
[
[
150,
94
],
"assets/images/resized/0004/3400/43400v1
-max-150x150.png"
],
[
[
250,
156
],
"assets/images/resized/0004/3400/43400v1
-max-250x250.png"
],
[
[
450,
282
],
"assets/images/resized/0004/3400/43400v1
-max-450x450.png"
]
],
"attribution": null
}],
"external_links": [],
"partners": []
} >
For the below query for our node.js app.
db.companies.aggregate([{
$match: {
"name": "Facebook"
},
$project: {
"_id": 0,
"name": 1,
"people": "$relationships.person.last_name"
}
}])
Gives the following error:
assert: command failed: {
"ok" : 0,
"errmsg" : "A pipeline stage specification object must contain exactly o ne field.",
"code" : 16435 } : aggregate failed
_getErrorWithCode#src/mongo/shell/utils.js:25:13 doassert#src/mongo/shell/assert.js:13:14
assert.commandWorked#src/mongo/shell/assert.js:267:5
DBCollection.prototype.aggregate#src/mongo/shell/collection.js:1312:5
#(shell):1:1
2016-09-17T19:20:26.303+0530 E QUERY [thread1] Error: command
failed: {
"ok" : 0,
"errmsg" : "A pipeline stage specification object must contain exactly o ne field.",
"code" : 16435 } : aggregate failed :
_getErrorWithCode#src/mongo/shell/utils.js:25:13 doassert#src/mongo/shell/assert.js:13:14
assert.commandWorked#src/mongo/shell/assert.js:267:5
DBCollection.prototype.aggregate#src/mongo/shell/collection.js:1312:5
#(shell):1:1
I'm unable to figure out why?

You are missing some braces for your aggregation pipeline operators. The correct pipeline should be:
db.companies.aggregate([
{ "$match": { "name": "Facebook" } }, /* match pipeline stage */
{ "$project": { /* project pipeline stage */
"_id": 0,
"name": 1,
"people": "$relationships.person.last_name"
} }
])

Related

How to filter the response from mongoDB, so nested arrays will include only items that meet a condition?

My documents look like this
{
"_id": {
"$oid": "62825f71005ce00c5f0235c1"
},
"user": "jon",
"roles": {
"User": 2001,
},
"STOCK ": [
{
"sku": "BLACK-M",
"productname": "BLACK",
"sendout": 0,
"recived": 1,
"totalinstock": 40,
"location": "B32",
"_id": {
"$oid": "62826016005ce00c5f0235c8"
}
},
{
"sku": "CJNS",
"productname": "89796363",
"sendout": 0,
"recived": 45,
"totalinstock": 0,
"location": "B232",
"_id": {
"$oid": "62836f2d56b4f1ac79c99b8d"
}
}
],
"ORDERS": [
{
"date": {
"$date": "2022-06-02T15:23:58Z"
},
"OrderNumber": "745607",
"City": "xxxxx",
"Address": "yyyyyy",
"Phone": "8678678678",
"Name": "Holly ",
"Trackingnumber": 40,
"ZipCode": 00000,
"Province": "New ",
"Quantity": [
1
],
"Product_Name": [
" pants pants"
],
"SKU": [
"CJNS"
],
"_id": {
"$oid": "6298d61ba6eeec72b78332a7"
}
},
{
"date": {
"$date": "2022-06-02T15:23:58Z"
},
"OrderNumber": "748840",
"City": "xxxxx",
"Address": "yyyyyy",
"Phone": "354353454",
"Name": "Michael",
"Trackingnumber": 0,
"ZipCode": 00000,
"Province": "North",
"Quantity": [
1
],
"Product_Name": [
" pants pants"
],
"SKU": [
"CJNS"
],
"_id": {
"$oid": "6298d61ba6eeec72b78332a9"
}
}
]
}
I successful to return all the objects in STOCK or all the objects in ORDERS
Through this query
const foundUser= await User.find({"user":req.body.user},("Orders") ).exec()
Now I want to filter the response to include only items where "Trackingnumber" is different from 0
For the sample data I expect to receive only
{
"date": {
"$date": "2022-06-02T15:23:58Z"
},
"OrderNumber": "748840",
"City": "xxxxx",
"Address": "yyyyyy",
"Phone": "354353454",
"Name": "Michael",
"Trackingnumber": 0,
"ZipCode": 00000,
"Province": "North",
"Quantity": [
1
],
"Product_Name": [
" pants pants"
],
"SKU": [
"CJNS"
],
"_id": {
"$oid": "6298d61ba6eeec72b78332a9"
}
}
You can use an aggregation pipeline with a $filter for this:
db.collection.aggregate([
{
$match: {
"user": "jon"
}
},
{
$project: {
ORDERS: {
$filter: {
input: "$ORDERS",
as: "item",
cond: {$ne: ["$$item.Trackingnumber", 0]}
}
}
}
}
])
Playground example
User.find({"Orders" : {"Trackingnumber": 0} })

Flter mongodb database using mongoose nodejs

I need to filter some users according to some fixed criteria. I have a user collection and a talent collection. The talent collection holds the reference to a master category collection.
What I need is to filter these users according to the category in the talent collection and some keys from the user collection.
For example I need to search for a user whose gender is 'male' and education 'BTech' and will have talents as a programmer and tester
my user collection is like,
{
"_id": "5f1939239bd35429ac9cd78f",
"isOtpVerified": "false",
"role": "user",
"adminApproved": 1,
"status": 0,
"languages": "Malayalam, Tamil, Telugu, Kannada",
"name": "Test user",
"email": "test#email.com",
"phone": "1234567890",
"otp": "480623",
"uid": 100015,
"bio": "Short description from user",
"dob": "1951-09-07T00:00:00.000Z",
"gender": "Male",
"education": "Btech",
"bodyType": "",
"complexion": "",
"height": "",
"weight": "",
"requests": [],
"location": {
"place": "place",
"state": "state",
"country": "country"
},
"image": {
"avatar": "5f1939239bd35429ac9cd78f_avatar.jpeg",
"fullsize": "5f1939239bd35429ac9cd78f_fullsize.png",
"head_shot": "5f1939239bd35429ac9cd78f_head_shot.jpeg",
"left_profile": "5f1939239bd35429ac9cd78f_left_profile.png",
"right_profile": "5f1939239bd35429ac9cd78f_right_profile.png"
},
"__v": 42,
"createdAt": "2020-07-23T07:15:47.387Z",
"updatedAt": "2020-08-18T18:54:22.272Z",
}
Talent collection
[
{
"_id": "5f38efef179aca47a0089667",
"userId": "5f1939239bd35429ac9cd78f",
"level": "5",
"chars": {
"type": "Fresher",
},
"category": "5f19357b50bcf9158c6be572",
"media": [],
"createdAt": "2020-08-16T08:35:59.692Z",
"updatedAt": "2020-08-16T08:35:59.692Z",
"__v": 0
},
{
"_id": "5f3b7e6f7e322948ace30a2c",
"userId": "5f1939239bd35429ac9cd78f",
"level": "3",
"chars": {
"type": "Fresher",
},
"category": "5f19359250bcf9158c6be573",
"media": [
{
"adminApproved": 0,
"status": 0,
"_id": "5f3c22573065f84a48e04a14",
"file": "id=5f1939239bd35429ac9cd78f&dir=test&img=5f1939239bd35429ac9cd78f_image_undefined.jpeg",
"description": "test",
"fileType": "image",
"caption": "test file"
},
{
"adminApproved": 0,
"status": 0,
"_id": "5f3c2d7a8c7f8336b0bfced2",
"file": "id=5f1939239bd35429ac9cd78f&dir=test&img=5f1939239bd35429ac9cd78f_image_1.jpeg",
"description": "this is a demo poster for testing",
"fileType": "image",
"caption": "A Test Poster"
}
],
"createdAt": "2020-08-18T07:08:31.532Z",
"updatedAt": "2020-08-18T19:35:22.899Z",
"__v": 2
}
]
And the category in the above document is a separate one populated to this. the category collection as,
[
{
"_id": "5f19359250bcf9158c6be573",
"status": true,
"title": "Testing",
"description": "Application tester",
"code": "test",
"characteristics": [],
"createdAt": "2020-07-23T07:00:34.221Z",
"updatedAt": "2020-07-23T07:00:34.221Z",
"__v": 0
},
{
"status": true,
"_id": "5f29829a705b4e648c28bc88",
"title": "Designer",
"description": "UI UX Designer",
"code": "uiux",
"createdAt": "2020-08-04T15:45:30.125Z",
"updatedAt": "2020-08-04T15:45:30.125Z",
"__v": 0
},
{
"_id": "5f19357b50bcf9158c6be572",
"status": true,
"title": "programming",
"description": "Java programmer",
"code": "program",
"createdAt": "2020-07-23T07:00:11.137Z",
"updatedAt": "2020-07-23T07:00:11.137Z",
"__v": 0
}
]
So my filter terms will be;
{
categories: ["5f19359250bcf9158c6be573", "5f19357b50bcf9158c6be572"],
minAge: 18,
maxAge: 25,
minHeight: 5,
maxHeight: 6,
minWeight: 50,
maxWeight: 80,
complexion: "white",
gender: "male",
}
And the expected result will be a user have both the above talents and followed conditions,
{
users: { ..User details.. },
medias: { ...medias from the matching talents.. }
}
If there are two collections you need to join them either by primary key or _id with foriegn fields and you can use $lookup with $match to filter down.
Documentation
You need to use $lookup with pipeline,
$match you condition for category match
$lookup to join users collection
$match conditions for users collections fields
$match exclude documents that don't found matching users of criteria passed in conditions
db.talents.aggregate([
{
$match: {
category: { $in: ["5f19359250bcf9158c6be573", "5f19357b50bcf9158c6be572"] }
}
},
{
$lookup: {
from: "users",
as: "users",
let: { userId: "$userId" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ["$$userId", "$_id"] },
{ $eq: ["$gender", "Male"] },
{ $eq: ["$education", "Btech"] }
// ... add you other match criteria here
]
}
}
}
]
}
},
{ $match: { users: { $ne: [] } } }
])
Playground

Issue with to get data from MongoDB aggregate

I want data from places where userid is equal to the body.user._id
PLACE DATA
{
"_id": "5e8ddd0f7f5b174290bbefc8",
"type": 0,
"location": [
24.8757396,
67.3464698
],
"title": "E 22, Steel Town Karachi, Karachi City, Sindh, Pakistan",
"googlePlaceId": "ChIJlbvA8BIzsz4Rlh7w_fKfwus",
"createdDate": "2020-04-08T14:17:51.869Z",
"__v": 0,
},
{
"_id": "5e8de4204396310017564a2b",
"type": 0,
"location": [
24.910688,
67.0310973
],
"title": "Nazimabad, Karachi, Pakistan",
"googlePlaceId": "ChIJzZudRr0_sz4R81KZ48Ylk3Q",
"createdDate": "2020-04-08T14:48:00.557Z",
"__v": 0,
},
{
"_id": "5e8de4364396310017564a2d",
"type": 0,
"location": [
24.9180271,
67.0970916
],
"title": "Gulshan-e-Iqbal, Karachi, Pakistan",
"googlePlaceId": "ChIJsda_CLg4sz4RIghXwgIae5k",
"createdDate": "2020-04-08T14:48:22.979Z",
"__v": 0,
},
{
"_id": "5e8dea79894854524cc554e0",
"type": 0,
"location": [
24.9343322,
67.177173
],
"title": "Malir Cantt Check Post No 6, Malir Link to Super Highway, Karachi, Pakistan",
"googlePlaceId": "ChIJJ7BbsyQ4sz4RvpkV9Ig_aU4",
"createdDate": "2020-04-08T15:15:05.360Z",
"__v": 0,
}**
Visited Places DATA
{
"_id":"5e90998f8bc84d0017a6d2f3",
"visitingNo":"0",
"_userId":"5e8f3ef5434f5800170c7169"
"_placeId":"5e908fdb8bc84d0017a6d2e8"
"createdDate":"2020-04-10T16:06:39.231+00:00"
"__v":"0"
},
{
"_id":"5e90998f8bc84d0017a6d2f3",
"visitingNo":"0",
"_userId":"5e8f3ef5434f5800170c7169"
"_placeId":"5e908fdb8bc84d0017a6d2e8"
"createdDate":"2020-04-10T16:06:39.231+00:00"
"__v":"0"
},
{
"_id":"5e90998f8bc84d0017a6d2f3",
"visitingNo":"0",
"_userId":"5e8f3ef5434f5800170c7169"
"_placeId":"5e908fdb8bc84d0017a6d2e8"
"createdDate":"2020-04-10T16:06:39.231+00:00"
"__v":"0"
},
MY CODE
const palace = placeData.aggregate([
{
$lookup:{
from: `${visitplaceData}`,
// localField: "_id",
// foreignField: "_placeId",
let : {
"placeId" : "$_id"
},
pipeline : [
{ $sort: { visitingNo : -1 } },
{
$match : {
$expr : {
$and : [
{$eq: [ "$_placeId", "$$placeId" ]},
{"_userId": body.user._id}
]
}
}
},
],
as: "places"
}
}
])

Mongoose aggregation with discriminator

I use CosmosDB Mongo API with only one collection using discriminators.
I'm now facing a problem where I want to "join" other collections into one.
My common collection is named "alldata" and has discriminator keys (_type) "Session", "Room" and "User".
Session contains "roomId" and "speakerIds" (Array of user ids).
Session object:
{
"singleEntrance": false,
"accreditationRequired": false,
"closed": false,
"usersAtended": [],
"speakerIds": [
"5b573723930d9751768f266e",
"5b586b6032063a70632721d8"
],
"archived": false,
"_type": "Session",
"_id": "5b586f81ae744a7266524f84",
"title": "Bla bla",
"about": "",
"type": "SIS1",
"track": "Special Interest Session",
"venue": "Bla 1",
"roomId": "5b5731e764f0de4f9e4082ac",
"from": "2018-10-22T10:00:00.015Z",
"to": "2018-10-22T12:00:00.015Z"
}
Result I want:
{
"singleEntrance": false,
"accreditationRequired": false,
"closed": false,
"usersAtended": [],
"spikeri": [
{* LIST OF USER OBJECTS *}
],
"archived": false,
"_type": "Session",
"_id": "5b586f81ae744a7266524f84",
"title": "Bla bla",
"about": "",
"type": "SIS1",
"track": "Special Interest Session",
"venue": "Bla 1",
"room": {
"_id": "5b5731e764f0de4f9e4082ac",
"archived": false,
"_type": "Room",
"name": "Bla 1",
"location": "Hotel Bla",
"createdAt": "2018-07-24T14:04:23.370Z",
"updatedAt": "2018-07-24T14:04:23.370Z",
"__v": 0
},
"from": "2018-10-22T10:00:00.015Z",
"to": "2018-10-22T12:00:00.015Z"
}
Room works fine, but I just cannot get User ("speakers") to work.
Finally, here's the code:
async getAgenda() {
return await Session.aggregate([
{
// this query returns all Sessions...
$match: {
$and: [
{ from: { $gte: new Date("2018-10-22T10:00:00.015Z") } },
{ to: { $lte: new Date("2018-10-22 17:00:00.015Z") } },
]
}
},
{
$lookup: { from: "alldata", localField: "roomId", foreignField: "_id", as: "room" }
},
{
$unwind: { path: '$room' }
},
{
$lookup: { from: "alldata", localField: "speakerIds", foreignField: "_id", as: "spikeri" }
}
])
}
Update: User object (speaker == User):
{
"_id": "5b2ba7784ad0f226d8ae2788",
"group": "USER",
"verified": true,
"eventsRegistered": [
"5b2b77b74ad0f226d8ae2780",
"5b27ca01cc7eff056826acc7"
],
"eventsAttended": [],
"tickets": [
"5b27cc43cc7eff056826accb",
"5b27d284cc7eff056826acd1",
"5b27cceecc7eff056826acd0"
],
"contacts": [],
"meetings": [],
"_type": "User",
"email": "bla#blabla.us",
"password": "...",
"countryCode": "HR",
"firstName": "Blaman",
"lastName": "Bla bla",
"role": "SPEAKER",
"createdAt": "2018-06-21T13:26:16.686Z",
"updatedAt": "2018-07-25T14:21:42.055Z",
"__v": 0
"confirmationCode": "5375159",
"transactionIds": [
"..."
],
"transactionId": "...",
"gender": "",
"jobTitle": "",
"companyAddress": "",
"companyName": "",
"postalCode": "",
"city": "",
"country": "Croatia"
}
Thank you for help in advance!

Synonyms, storing weights in document for relevance scoring in Elastic Search

The story: Given the example documents below and by extending them, is it possible to get the following ranking:
A search on "Cereals" results in the following ranking
Cornflakes
Rice Krispies
A search on "Rice" results in the following ranking
Basmati
Rice Krispies
The documents against the search is performed:
[{
name: "Cornflakes"
},
{
name: "Basmati"
},
{
name: "Rice Krispies"
}]
Of course, some of them does not even held the search term, so an option is to add an array of synonyms with a text value and weight with would help in computing the ranking:
[{
name: "Cornflakes",
synonyms: [
{t: 'Cereals', weight: 100},
{t: 'Sugar', weight: 100}]
},
{
name: "Basmati",
synonyms: [
{t: 'Cereals', weight: 1},
{t: 'Rice', weight: 1000}]
},
{
name: "Rice Krispies",
synonyms: [
{t: 'Cereals', weight: 10},
{t: 'Rice', weight: 1}]
}]
Is it the right approach?
What is the Elastic Search query for taking into account weighted synonyms?
I think "tags" would be a more appropriate name for the field than "synonyms".
You could use a nested type to store tags and use function score to combine the value of the tags.weight field (of the best matching tag if any) with the match score on the name field.
One such implementation could look as follows:
put test
put test/tag_doc/_mapping
{
"properties" : {
"tags" : {
"type" : "nested" ,
"properties": {
"t" : {"type" : "string"},
"weight" : {"type" : "double"}
}
}
}
}
put test/tag_doc/_bulk
{ "index" : { "_index" : "test", "_type" : "tag_doc", "_id":1} }
{"name": "Cornflakes","tags": [{"t": "Cereals", "weight":100},{"t": "Sugar", "weight": 100}]}
{ "index" : { "_index" : "test", "_type" : "tag_doc","_id":2} }
{ "name": "Basmati","tags": [{"t": "Cereals", "weight": 1},{"t": "Rice", "weight": 1000}]}
{ "index" : { "_index" : "test", "_type" : "tag_doc","_id":3} }
{ "name": "Rice Krispies", "tags": [{"t": "Cereals", "weight": 10},{"t": "Rice", "weight": 1}]}
post test/_search
{
"query": {
"dis_max": {
"queries": [
{
"match": {
"name": {
"query": "cereals",
"boost": 100
}
}
},
{
"nested": {
"path": "tags",
"query": {
"function_score": {
"functions": [
{
"field_value_factor": {
"field": "tags.weight"
}
}
],
"query": {
"match": {
"tags.t": "cereals"
}
},
"boost_mode": "replace",
"score_mode": "max"
}
},
"score_mode": "max"
}
}
]
}
}
}
Result :
"hits": {
"total": 3,
"max_score": 100,
"hits": [
{
"_index": "test",
"_type": "tag_doc",
"_id": "1",
"_score": 100,
"_source": {
"name": "Cornflakes",
"tags": [
{
"t": "Cereals",
"weight": 100
},
{
"t": "Sugar",
"weight": 100
}
]
}
},
{
"_index": "test",
"_type": "tag_doc",
"_id": "3",
"_score": 10,
"_source": {
"name": "Rice Krispies",
"tags": [
{
"t": "Cereals",
"weight": 10
},
{
"t": "Rice",
"weight": 1
}
]
}
},
{
"_index": "test",
"_type": "tag_doc",
"_id": "2",
"_score": 1,
"_source": {
"name": "Basmati",
"tags": [
{
"t": "Cereals",
"weight": 1
},
{
"t": "Rice",
"weight": 1000
}
]
}
}
]
}

Resources