MongoDb match an unknown number of different values - node.js

I am trying to extract some data out of a MongoDB.
My DB looks something like this;
{
"name": "A",
"address": "London Road",
"values": [{"id": 1234, "name":"ABCD"},{"id": 6784, "name":"test"}]
}
{
"name": "B",
"address": "South Road",
"values": [{"id": 4327, "name":"guest"},{"id": 6743, "name":"demo"}]
}
{
"name": "C",
"address": "North Road",
"values": [{"id": 1234, "name":"ABCD"}]
}
I am trying to extract data based on the values id key.
So if I match 1234 to values id i'll return Elements A and C - I am able to do this.
The values I want to match may change, they could be 1234 or 6743 - returning Elements A, B and C.
I have created the below $or to handle this however the number of values to match varies, so the number of $or functions should change dependent on the number of values to match.
How do I create a query that allows me to match an unknown number of different values? - Maybe a loop?
Thanks in advance. I have search SO and the net and haven't had much success!
const orders = await findr.find({
$or: [{
values: {
$elemMatch: {
id: "1234",
}
}
},
{
values: {
$elemMatch: {
id: "6743",
}
}
}
]
}).toArray()

You can write the query using $in: {"values.id": { $in: ["123", "456"] }}
$elemMatch isn't necessary because you're only specifying a single criterion.

Related

PouchDB/CouchDB Group By Value in Array

I am using PouchDB and I have a dataset representing a social network in a graph. People are documents, and the people they follow are in an array of the _id of the person followed. Here is a sample of the data:
[
{
"_id": "mc0001",
"name": "Jill Martin",
"joined": "2020-01-15",
"follows": []
},
{
"_id": "mc0002",
"name": "Elena Markova",
"joined": "2020-01-21",
"follows": ["mc0001"]
},
{
"_id": "mc0003",
"name": "Carlos Sanchez",
"joined": "2020-01-27",
"follows": ["mc0001", "mc0002"]
},
{
"_id": "mc0004",
"name": "Ai Sato",
"joined": "2020-02-21",
"follows": ["mc0001", "mc0003"]
},
{
"_id": "mc0005",
"name": "Ming Wu",
"joined": "2020-03-21",
"follows": ["mc0002", "mc0003", "mc0004"]
}
]
What I would like to do is query for each person, and get a list of followers. I am looking for something like this:
[
{
"_id": "mc0001",
"followers": ["mc0002", "mc0003", "mc0004"]
},
{
"_id": "mc0002",
"followers": ["mc0003", "mc0005"]
},
{
"_id": "mc0003",
"followers": ["mc0004", "mc0005"]
},
{
"_id": "mc0004",
"followers": ["mc0005"]
},
{
"_id": "mc0005",
"followers": []
}
]
Is there a way to do this without changing the data structure (e.g. moving the followers array into the doc of the person being followed)?
Create a Map/Reduce view that loops through the follows array in each document and emits those; like this:
function (doc) {
for(var i =0; i<doc.follows.length; i++) {
emit(doc.follows[i], null);
}
}
You end up with an index keyed on a user and where each row has the id of a follower of that user. You can then query the index, supplying the key of the user whose followers you want to find, like this:
$URL/users/_design/users/_view/by-follower?key="mc0001"&reduce=false
You will get something like this:
{"total_rows":8,"offset":0,"rows":[
{"id":"mc0002","key":"mc0001","value":null},
{"id":"mc0003","key":"mc0001","value":null},
{"id":"mc0004","key":"mc0001","value":null}
]}
This is not exactly the format of the data you have in your question, but you can see that the id field in each object contains a follower of your desired user, so you can go from there.

Destructuring a Sequelize query

I'm having trouble deconstructing a simple Sequelize query.
const character = await Character.findAll({
order: ['created_at'],
attributes: ['id', 'name', 'created_at'],
});
I want to access the "created_at" of the list, but I try to
const { created_at } = character;
But it returns undefined.
I need to subtract the current date from the created_at date.
Could someone tell me what I'm doing wrong or how could I do it?
I have Moment.js installed if needed.
Query return
{ "id": 10, "name": "John Doe", "created_at": "2020-08-08T20:52:06.262Z" },
{ "id": 11, "name": "Mary Jane", "created_at": "2020-08-08T21:01:49.562Z" },
{ "id": 12, "name": "Clark Kent", "created_at": "2020-08-08T21:02:51.948Z" }
]
In you case you are trying to do a destructuring from an array. But it only works in an object.
To it to work you should use an index.
Something like:
const { created_at } = character[0];
Notice that it will only destruct the position zero from your results contained in the character array. If you do not would like the position zero you should use another function to choose the desired result.

Mongoose how to find specific value

After a lot of reading, I am stuck.
the code I posted here, is the implementation of a store database I am trying to make.
in every store, we have some fields. I am interested in doing something with the items array, that contains JSON variables.
I want to filter the items through three filters, firstly by the store ID, secondly by the category ID, and the last filter will be the semi category ID.
I want to send the data from the front end, meaning I supply STOREID, the CategoryID, and the SemiCategoryID.
after receiving the data at the back end side, I am expecting to receive only the relevant items according to the data supplied by the front end.
{
"_id": {
"$oid": "5a1844b5685cb50a38adf5bb" --> **ID of the STORE**
},
"name": "ACE",
"user_id": "59e4c41105d1f6227c1771ea",
"imageURL": "none",
"rating": 5,
"items": [
{
"name": "NirCohen",
"categoryID": "5a0c2d292235680012bd12c9",
"semiCatID": "5a0c2d5a2235680012bd12ca",
"_id": {
"$oid": "5a1958181cd8a208882a80f9"
}
},
{
"name": "he",
"categoryID": "5a0c2d292235680012bd12c9",
"semiCatID": "5a0c2d5a2235680012bd12ca",
"_id": {
"$oid": "5a1973c40e561e08b8aaf2b2"
}
},
{
"name": "a",
"categoryID": "5a0c2d292235680012bd12c9",
"semiCatID": "5a0c2d5a2235680012bd12ca",
"_id": {
"$oid": "5a197439bc1310314c4c583b"
}
},
{
"name": "aaa",
"categoryID": "5a0c2d292235680012bd12c9",
"semiCatID": "5a0c2d5a2235680012bd12ca",
"_id": {
"$oid": "5a197474558a921bb043317b"
}
},
],
"__v": 9
}
and I want the Backend to return the filtered items according to the query.
The problem is, I am not managing to get the CORRECT query.
your help will be much appreciated,
thank you in advance.
If I understand you correctly, you are doing something like this:
Store.find({}).then(..);
If you only want to find the stores where categoryID is equal to the variable myCategory, you could filter them out by using:
Store.find({semiCatID: myCategory}).then(..);
Please let me know if this is not what you are after, then we can keep trying to figure this out together.
EDIT: So you are sending the variables StoreID, CategoryID and SemiCategoryID from the frontend. Receive them in the backend, and want to filter your database collection matching all three fields?
If so.. then I think all you have to do is change your current query:
store.findOne({ _id: req.body.userID }, (err, store) => { console.log(store); });
To something like:
store.findOne({
_id: req.body.userID,
storeID: req.body.StoreID,
categoryID: req.body.CategoryID,
semiCategoryID: req.body.SemiCategoryID
}, (err, store) => { console.log(store); });
This way, the objects you get back from mongo must match all four criterias given from the frontend.
As far as I Understood your question here is my answer to it you can use findById
Store.findById({//store id}).then(..);
or
Store.findOne({_id:ObjectID(storeID)}).then(..);

How to use mongodb aggregation to transform document in nested array

My document looks like as shown below and I want to transform it using aggregation. Inside favourite_products I have product array and it has product_id corresponding to each shops. Now I just want product ids of all shops but sorted based on time. :
"favourite_products": [
{
"shop": {
"shop_id": "59465888f7babb000485574b",
"time": "2017-07-12T06:11:19.817Z"
},
"product": [
{
"product_id": "594c2d56f7afcf00043b1195",
"time": "2017-07-12T06:10:36.775Z"
},
{
"product_id": "594ac36c76de720004e819f6",
"time": "2017-07-12T06:11:19.817Z"
}
]
},
{
"shop": {
"shop_id": "593acc24a2902d0004211f1f",
"time": "2017-07-12T06:12:59.372Z"
},
"product": [
{
"product_id": "594ac36c76de720004e819f6",
"time": "2017-07-12T06:12:59.372Z"
}
]
}
]
I want to transform it into this:
"favourite_products"
["59465888f7babb000485574b",594c2d56f7afcf00043b1195","594ac36c76de720004e819f6","593acc24a2902d0004211f1f","594ac36c76de720004e819f6"]
Below returns time ordered documents of favourite_products.product.product_id
use project if you want the result as different documents.
or use group if you want the result as the array in one document.
db['testing-aggregate'].aggregate([
{$unwind:'$favourite_products'},
{$unwind:'$favourite_products.product'},
{$sort:{'favourite_products.product.time':1}}, // order by time. 1=ascending | -1=descending
// {$project:{
// '_id':0, // exclude _id from output
// 'favourite_products':'$favourite_products.product.product_id' // return only product_id
// }},
{$group:{
_id:null,
product_id:{$push:'$favourite_products.product.product_id'}
}}
])

Searching many parameters in a Cloudant noSQL DB

I am using a Cloudant database on Bluemix to storage products in a Node.js server. These products will be searched by categories. To find a product that has only one category, would not be a problem because a search is made by comparing the string that is sent as a search parameter with the category string that is saved in the database. The problem occurs when a product has two or more categories. At the time of making the comparison of string to string, it would never coincide.
The products can have as many categories as they need.
Any ideas?
if i am understanding your question correctly, you may want to store category as an array of strings and index each element in the array. you can then search products against a single or multiple categories.
for example, given the following documents:
doc 1
{
"name": "product1",
"category: ["abc"]
}
doc 2
{
"name": "product2",
"category: ["abc", "def"]
}
you can set up a search index similar to:
function (doc) {
if (doc.category) {
for (var i in doc.category) {
index("category", doc.category[i], {"store": true, "facet": true})
}
}
}
then you may run queries like such:
.../{dbname}/_design/{designdocname}/_search/{searchindexname}?q=category:abc
which would return both product1 and product2
or:
.../{dbname}/_design/{designdocname}/_search/{searchindexname}?q=category:abc+AND+category:def
which would return only product2.
additional info: https://developer.ibm.com/clouddataservices/cloudant-search/
You should store one or more categories in array format in Cloudant database in "category" parameter
{
"_id": "producto1",
"category: ["TV", "cameras", "computers"]
}
Then you should create a search index
function (doc) {
if (doc.category) {
for (var i in doc.category) {
index("category", doc.category[i], {"store": true, "facet": true})
}
}
}
Now you can query the documents from Cloudant Query
{
"selector": {
"_id": {
"$gt": 0
},
"category": {
"$all": [
"TV",
"cameras"
]
}
},
"fields": [
"_id",
"_rev"
],
"sort": [
{
"_id": "asc"
}
]
}
Or you can use
https://{url_database}/{name_database}/_design/{name_design}/_search/{name_search}?q=category:TV

Resources