MongoDB - Get an unique array from two queries - database

First of all sorry if the title does not reflect what I really need to do.
Imagine a collection that represents what products sell which vendor. Let´s simplify like:
{_id, productID, VendorID, Price, Stock}
For example, we could have:
{_id: 1 ,productID: 1, vendorID: A, price: 0, stock: 0},
{_id: 2 ,productID: 2, vendorID: A, price: 0, stock: 0},
{_id: 3 ,productID: 3, vendorID: A, price: 0, stock: 0},
{_id: 4 ,productID: 4, vendorID: A, price: 0, stock: 0},
{_id: 5 ,productID: 1, vendorID: B, price: 0, stock: 19},
{_id: 6 ,productID: 3, vendorID: B, price: 0, stock: 21}
The idea is that Vendor A is the Super Admin and the one who controls which products can be sold in the marketplace. That´s why all products sold by A have price = 0 and stock = 0.
What I am trying to get within the same query is. When Vendor B is logged:
List all the items that A is selling.
But if a product is sold by B, then I should return it instead of the A-one.
The result would look like:
{_id: 2 ,productID: 2, vendorID: A, price: 0, stock: 0},
{_id: 4 ,productID: 4, vendorID: A, price: 0, stock: 0},
{_id: 5 ,productID: 1, vendorID: B, price: 0, stock: 19},
{_id: 6 ,productID: 3, vendorID: B, price: 0, stock: 21}
Do you have any idea how I can do it in a shot?
I can do the filter in the frontend but I would prefer doing like this in order to avoid problems with pagination for example.

If you are sure that all products sold by A always have price = 0 and stock = 0, you can do the following trick:
db.collection.aggregate({
$match: {
vendorID: {
$in: [
"A",
"B"
]
}
}
},
{
$sort: {
productID: 1,
price: -1
}
},
{
"$group": {
"_id": "$productID",
"product": {
$first: "$$ROOT"
}
}
})
Mongo playground
by $match you are looking for all products owned by default vendor (A) and target vendor (B).
by $sort you group products by productID and by price in each group, so product sold by A will be last one in each group
by $group you extract product from each group
using $first it will be first product (with higher price, so product sold by A will be matched only if no other products with same ID were sold).
DB documents will be aggregated by $$ROOT into product field, so you can map them using:
// (javascript)
const productDocuments = aggregationResult.map(row => row.product);
Notice: product sold by A still can be extracted even if B sold product with same ID in cases when B's product also have price = 0.

Related

How sort when have array with name and score mongodb

I have a document with users and each user haves "categories" and "tags", in both as at next:
[
{user_id: 1, categories:[
{category: uuidv4x1, score:75},
{category: uuidv4x2, score:67}
],
tags: [
{tag: "1ne", score:15},
{tag: "subjetive", score:89}
]}
How can order by category, tag but too by score, if i have:
[
{id: 1, category: uuidv4x6, tags:["1ne", "optimized"]},
{id: 2, category: uuidv4x2, tags:["1ne", "subjetive"]},
{id: 3, category: uuidv4x1, tags:["home", "car"]}
]
Before to all, thanks so much.
I expect sort my find for better matches, customize articles.

Using Map Object to Render React Components in Order

I receive an array of product objects like such from my backend.
products = [
{id: 1, price: 10, category: "food", name: "apples"},
{id: 2, price: 5, category: "supplies", name: "spoons"},
{id: 3, price: 15, category: "pets", name: "cat treats"},
{id: 4, price: 9, category: "food", name: "oranges"},
// ...
]
I am looking to render all my products as strips based on their category in a specific order of priority (similar to how Netflix aligns their shows). I don't want them displayed in random order, such as the category strip of food being at the top, the next category strip being pets, etc.
I currently decided to create a map object since it keeps order as followed:
let filteredProducts = new Map([
["food", []],
["pets", []],
["supplies", []],
// ...
])
for (let product of products) {
let category = product["category"]
filteredProducts.get(category).push(product)
}
The goal is to then iterate through the map object and return multiple React Component of category strips from top to bottom.
My question is, I can't help but feel that there are more efficient ways to render this as I don't see map objects being utilized commonly. Are there more efficient and frequently used ways to filter and render by priority or is this in the right direction?
I do believe there is more easier way to do this using Array sort function.
Please consider the snippet below.
const products = [
{id: 1, price: 10, category: "food", name: "apples"},
{id: 2, price: 5, category: "supplies", name: "spoons"},
{id: 3, price: 15, category: "pets", name: "cat treats"},
{id: 4, price: 9, category: "food", name: "oranges"},
// ...
]
const priority = [
'food',
'supplies',
'pets'
]
const orderedProducts = products.sort(
(p1, p2) => priority.indexOf(p1.category) - priority.indexOf(p2.category)
);
Let me know if this looks much cleaner & easier approach.

react awesome query builder limitations with mongodb and embedded doc collections

I have 2 collections, Authors and Books and I want to use react-awesome-query-builder to enable the user to query the data however they like, here are my schemas and data
Authors collection
{id: 1, name: 'JK Rowling', gender: 'F'},
{id: 2, name: 'Roald Dahl', gender: 'M'},
{id: 3, name: 'Dr Seuss', gender: 'M'}
Books collection
{id: 1, author_id: 1, title: 'Harry Potter and the Philosophers Stone', year: 1997},
{id: 2, author_id: 1, title: 'Harry Potter and the Goblet of Fire', year: 2000},
{id: 3, author_id: 2, title: 'Charlie and the Chocolate Factory', year: 1964},
{id: 4, author_id: 2, title: 'James and the giant peach', year: 1961},
{id: 5, author_id: 3, title: 'Green eggs and ham', year: 1960},
{id: 6, author_id: 3, title: 'The cat in the hat', year: 1957}
I want to be able to build query to 'show me all authors that released books in the 1960s', and it return me the mongo query allows me to query, which when executed returns the following results:
{id: 2, name: 'Roald Dahl'},
{id: 3, name: 'Dr Seuss'}
I am not sure how to arrange my data, one collection of 'authors' with embedded array of 'books' documents, or two separate collections or a combination of the two?
Mongo works well with embedded documents but not sure of the capability of react-awesome-query-builder?
It appears that $elemmatch support has been added to react-awesome-query-builder so I just needed to change my !struct config to !group and voila!

AngularJS Sum values in quantity field base on part number

I have an array similar to this:
[
{part_number: 1, station: 300, description: "cable", qty: 40},
{part_number: 1, station: 40, description: "cable", qty: 20},
{part_number: 2, station: 300, description: "monitor", qty: 12},
{part_number: 3, station: 40, description: "mounting bracket", qty: 33},
]
I am displaying the items with ngRepeat and filtering for unique part number. For each part_number listed, I need to find the qty of each part at the multiple stations and display it in the qty field of that line.
For example:
Part 1 has a total qty of 60, 40 at station 300 and 20 at station 40. Part 2 has a total qty of 12 at station 300. Part 3 has a total qty of 33 at station 40.
I am not sure how to get these quantities or how to display them properly by part number. Any help would be appreciated.
EDIT(1):
Sorry to make this so vague which makes it look like I haven't even tried. I have been looking at higher order functions, but cannot determine which ones I should use in conjunction to achieve this end.
Would it be possible to use .map to add a "qty" key/value pair to each object in the array...then simply add an expression in my view to show this value?
I need to get the accumulated quantity of the duplicated parts before I set this value in the uniquely filtered array.
You need to loop through your array and calculate sum. You can try the following
html
<div ng-repeat="item in result">
{{item.description}}({{item.part_number}}) - {{item.qty}}
</div>
js
$scope.data = [
{part_number: 1, station: 300, description: "cable", qty: 40},
{part_number: 1, station: 40, description: "cable", qty: 20},
{part_number: 2, station: 300, description: "monitor", qty: 12},
{part_number: 3, station: 40, description: "mounting bracket", qty: 33}
];
$scope.result = [];
$scope.data.reduce(getSum, {});
function getSum(result, item) {
if (!result[item.part_number]) {
result[item.part_number] = { part_number: item.part_number, qty: 0 ,description: item.description};
$scope.result.push(result[item.part_number])
}
result[item.part_number].qty += item.qty;
return result;
}
Demo

Merge two arrays of objects in Ruby

I have an array of objects with unique IDs:
[{id: 1, score: 33}, {id: 23, score: 50}, {id:512, score: 27}, ...]
I also have an array of User records with matching IDs. The user records have "name" but not "score":
[{id: 1, name: "Jon"}, {id: 23, name: "Tom"}, {id: 512, name: "Joey"}, ...]
How can I create a single array with each id, name, and score?
[{id: 1, name: "Jon", score: 33}, {id: 23, name: "Tom", score: 50}, {id: 512, name: "Joey", score: 27}, ...]
I tried merge, combine, filter, etc but haven't found the Ruby function to accomplish this.
Assuming that in users there is always record with corresponding :id from scores:
scores = [{id: 1, score: 33}, {id: 23, score: 50}, {id:512, score: 27}]
users = [{id: 1, name: "Jon"}, {id: 23, name: "Tom"}, {id: 512, name: "Joey"}]
scores = scores.map { |score| score.merge(users.find { |user| user[:id] == score[:id] }) }
# => [{:id=>1, :score=>33, :name=>"Jon"}, {:id=>23, :score=>50, :name=>"Tom"}, {:id=>512, :score=>27, :name=>"Joey"}]
Hope that puts you in proper direction!
You can use an intermediate Hash.
hsh = Hash[ a1.map {|h| [h[:id], h[:score]]} ]
# => {1=>33, 23=>50, 512=>27}
a2.map {|h| h[:score] = hsh[h[:id]]; h}
# => [{:id=>1, :name=>"Jon", :score=>33}, {:id=>23, :name=>"Tom", :score=>50}, {:id=>512, :name=>"Joey", :score=>27}]
If, as in the example, scores[i][:id] = users[i][:id] for all i, and you are using v1.9+ (where key insertion order is maintained), you could write:
scores.zip(users).each_with_object({}) do |(sh,uh),h|
h.update(sh).update(uh)
end
Would I use this? Would you?

Resources