How should I do an aggregate? - javascript

I have an array with products(objects) inside. It looks like:
[
{_id: 123, name:'first', category:'Vape', property:[
{key:'brand', values:'Eleaf'},
{key:'mechmode', values:'some'},
{key:'color', values:['red', 'blue']},
{key:'batrtype', values:'some2'},
]},
{_id: 1234, name:'second', category:'Vape1', property:[
{key:'brand', values:'Eleaf1'},
{key:'mechmode', values:'some'},
{key:'color', values:['black']},
{key:'batrtype', values:'some2'}
]},
{_id: 12345, name:'third', category:'Vape3', property:[
{key:'brand', values:'Eleaf3'},
{key:'mechmode', values:'some'},
{key:'color', values:['green', 'yellow']},
{key:'batrtype', values:'some2'}
]},
{_id: 123456, name:'fourth', category:'Vape', property:[
{key:'brand', values:'Eleaf'},
{key:'mechmode', values:'some'},
{key:'color', values:['red', 'green']},
{key:'batrtype', values:'some2'}
]}
]
Request from client
{category:'Vape', body:{brand:'Eleaf', color:'red'}}
How should I do an aggregate in mongo to get products which have brand = 'Eleaf'
and color = red in according to request?
Can somebody help please?

bgraham's answer is exactly right if you are using find. To do the same thing in an aggregation pipeline, use $match, such as:
db.aggregate([{$match:{
category: "Vape",
$and: [
{ property: { $elemMatch: { key: "brand", value: "Eleaf" },
{ property: { $elemMatch: { key: "color", value: "red" }
]
}}])
You could then add to the array any additional pipeline stages you need.

I think this should do the trick:
db.products.find({
category: "Vape",
$and: [
{ property: { $elemMatch: { key: "brand", value: "Eleaf1" },
{ property: { $elemMatch: { key: "color", value: "red" }
]})
I'm not sure the structure of your data is best practice. It might be easier if they were fields called "brand" with a value of "color" instead of key/value pairs.

Related

Match by multiple objects in array in Mongoose

My data looks like this
{
"_id": "62f77d806f24c09f0acae163",
"name": "Test product",
"attributes": [
{
"attribute_name": "Shape",
"attribute_value": "Square"
},
{
"attribute_name": "Color",
"attribute_value": "Red"
}
]
}
I am using the aggregate method to filter results where I want to find products where "attribute_name" is "shape" and the "attribute_value" is "Square" AND "attribute_name" is "Color" and the "attribute_value" is "Red"
Basically I am building a filter feature in my application and basis the data passed to the API I want to get the products.
I have tried this:
let lookup = {
$match: {
$and: [
{
'attributes.attribute_label': 'Shape',
'attributes.attribute_value': {
$in: ['Square']
},
},
{
'attributes.attribute_label': 'Color',
'attributes.attribute_value': {
$in: ['Red']
},
}
],
}
};
let products = await productsModel.aggregate(lookup);
At first it seemed like it worked, but then I noticed it doesn't work properly, it matches
'attributes.attribute_value': {
$in: ['Red']
},
so if it finds "Red" in "attribute_label" which can be anything other than "Color" it will still return the results.
Any help is appreciated
I want to be able to get results based on the values for each attribute name
For e.g data passed might be this
Shape=Square,Color=Red,Green
I want to get the products which matches this, where the object with attribute_label of Color contains the attribute_value of Red or Green.
Is it a typo? Once you are using "attributes.attribute_label" and once "attributes.attribute_name".
This should work with attributes.attrubite_name (not label!)
[
{
'$match': {
'$and': [
{
'attributes.attribute_name': 'Shape'
}, {
'attributes.attribute_value': {
'$in': [
'Square'
]
}
}, {
'attributes.attribute_name': 'Color'
}, {
'attributes.attribute_value': {
'$in': [
'Red'
]
}
}
]
}
}
]

Mongoose : get content of multiple subdocument in one object

Hello I've been trying to select all the subdocument of multiple document returned in ONE single object and if it's possible sorted by value.
Here is what I mean :
My collection :
{
userId: 1,
...
items : [
{name: "candle", value:5},
{name: "shoes", value: 200}
]
},
{
userId: 2,
...
items : [
{name: "burger", value:17},
{name: "car", value: 5000}
]
},
{
userId: 3,
...
items : [
{name: "chips", value:2},
]
}
And I want to make a query that return me something like that :
[
{userId:1, name: "candle", value:5},
{userId:1, name: "shoes", value: 200},
{userId:2, name: "burger", value:17},
{userId:2, name: "car", value: 5000},
{userId:3, name: "chips", value:2}
]
I've been trying this :
Mymodel.find({}).select("items"); //It return me all the items but in separate object. [ {items: []} ...]
Also if it is possible I would like to sort them : I want to get the 3 most valuable items in the users collection. I tried to use the aggregate method following some example in the mongoose doc but I didn't succeed to make it work. I also have been thinking to make a new database containing only the users items so I can sort them easily but I feel like there is a better solution to do this.
So my question is do you have an idea how could I make it work ? thank you in advance
I'm pasting just an option
var pipeline = [
{
"$unwind" : "$items"
},
{
"$addFields" : {
"name" : "$items.name",
"value" : "$items.value"
}
},
{
"$unset" : "items"
},
{
"$project" : {
"_id" : 0,
"name" : 1,
"value" : 1,
"userId" : 1
}
}
]
Run db.collname.aggregate(pipeline) or review the syntax for the driver.

How to create following type of json that will usefull in type ahead with angular js

I have successfully implement type ahead using angular js using this codepen.
Now my data is dynamic so I want to create my own json that should looks something like following:
$scope.states = [
{
name: "ABCD",
id: "AB"
},
{
name: "XYZ",
id: "XY"
},
{
name: "OPQR",
id: "OP"
},
{
name: "LMNO",
id: "LM"
},
{
name: "KLM",
id: "KL"
}
];
How to create like above json and store in $scope variable so I can access it using name and id separately.
Please help me...!!
I am giving by my own now cause I got it little bit late.
Solution is I have pushed the data wrong I have solved it like:
$scope.states.push({
name: "string",
id: int,
});
and I got it.

Filter Json in Code AngularJS

Hello I have the following JSONs
$scope.Facilities=
[
{
Name: "-Select-",
Value: 0,
RegionNumber: 0
},
{
Name: "Facility1",
Value: 1,
RegionNumber: 1
},
{
Name: "Facility2",
Value: 2,
RegionNumber: 1
},
{
Name: "Facility3",
Value: 3,
RegionNumber: 2
}
];
$scope.Regions=
[
{
Name: "-Select-",
RegionNumber: 0
},
{
Name: "USA",
RegionNumber: 1
},
{
Name: "Mexico",
RegionNumber: 2
}
];
I would have two DropdownLists in my app which will have one of these Jsons assigned to it.
Whenever you select a Region, a ng-change would be triggered. What I want, is to make the Facility DDL to update it's values. It would only show the Facilities which have a RegionNumber equivalent to the selected Region's RegionNumber.
How could I achieve this? I'm using Angular JS, MVC...
Note: The -Select- Value must always appear, even if it's value is zero and is not equivalent to the selected Region.
While a data structure, like greengrassbluesky may simplify the result, you can accomplish the same thing with an onchange that leverages javascript filtering
$scope.Facilities = masterFacilities.filter(function (el) {
return regionNumber = el.RegionNumber == $scope.SelectedRegion || el.RegionNumber == 0;
});
Here's a fiddle with an example using your lists.
I think you need a data structure like below:
$scope.Regions=
[
{
Name: "-Select-",
facilities : {
facilityId: 1,
facilityName: "facility1"
},
{
facilityId: 2,
facilityName: "facility2"
}
},
{
Name: "USA",
facilities : [{
facilityId: 1,
facilityName: "facility1"
},
{
facilityId: 2,
facilityName: "facility2"
}]
},
];
So, you could reference them like below:
For the dropdown of Regions, you can iterate through above Data structure.
Store the selectedRegion in selectedRegion
Then use that for the dropdown for facilities.

MongoDB aggregate() .$unwind

I have some data that looks like this (not real data):
{
_id:'cust04',
name:'Diarmuid Rellis',
address:'Elysium, Passage East',
county:'Waterford',
phone:'051-345786',
email:'dreil#drarch.com',
quotations:[
{
_id:'quot03',
supplier_ref:'A2006',
date_received: new Date('2013-05-12T00:00:00'),
date_returned: new Date('2013-05-15T00:00:00'),
supplier_price:35000.00,
customer_price:35000.00,
orders:[
{
_id:'ord03',
order_date: new Date('2013-05-20T00:00:00'),
del_date: new Date('2013-08-12T00:00:00'),
del_address:'Elysium, Passage East, Co. Waterford',
status:'BALPAID'
}
]
},
{
_id:'quot04',
supplier_ref:'A2007',
date_received: new Date('2013-08-10T00:00:00'),
date_returned: new Date('2013-08-12T00:00:00'),
supplier_price:29600.00,
customer_price:29600.00,
orders:[
{
_id:'ord04',
order_date: new Date('2014-03-20T00:00:00'),
del_date: new Date('2014-05-12T00:00:00'),
del_address:'Elysium, Passage East, Co. Waterford',
status:'INPROD'
}
]
}
]
}
I am trying to unwind the quotations and orders arrays, and get a projection of all orders in production which include the customer name, supplier_ref and order date for each.
Here is my query:
db.customers.aggregate([
{ $unwind: "$quotations" },
{ $unwind: "$quotations.orders" },
{ $match: { 'quotations.orders.status': 'INPROD' } },
{
$project: {
name: 1,
supplier_ref: "$quotations.supplier_ref",
order_id: "$quotations.orders._id",
order_date: "$quotations.orders.order_date"
}
},
{
$group: {
_id: "$order_id"
}
}
], function (err, results) {
console.log(results);
})
The query runs successfully, but just gives the order ids, not any of the other fields required. What am I missing ?
EDIT
I am hoping for a result like:
"result": [
{
"_id" : "orderid01",
"name" : "Joe Bloggs",
"supplier_ref" : "A1234",
"date_ordered" : "2012-04-14"
},
{
"_id" : "orderid02",
"name" : "Joe Bloggs",
"supplier_ref" : "A1235",
"date_ordered" : "2012-04-16"
}
]
When I add an extra field to my 'group' function, like so:
$group: {
_id: "$order_id",
supplier_ref: "$supplier_ref"
}
I get the error: "the group aggregate field 'supplier_ref' must be defined as an expression inside an object". Do I have to associate it with the result object in some way ?
Removing the group function altogether produced the results I wanted.

Categories