Mongoose partial text search with sorting by revelance - javascript

I'm trying to query my mongodb database via mongoose, sorting the most relevant items first.
The following code works, but only returns results that contain the search parameter as a full word.
E.g. example will return items that include fields such as, ⁣ but{name: "example-item", description: "this is an example description"} but examp won't return that same item. I'd also like for it to search across multiple fields, as my current code does.
I'm aware you can do this partial search using regex but then you're not able to sort by textScore. Is there any way to do both? Sorting after each request is not possible as it will be paginated and handling somewhat large data.
let searchValue = "examp";
let matchingItems = await Items.find(
{
$text: {
$search: searchValue,
}
},
{
score: {
$meta: "textScore"
}
},
{
sort: {
score: {
$meta: "textScore"
}
}
}
);
Example DB data:
[
{name: "dignissim", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."},
{name: "Fusce eget.", description: "Nullam malesuada ex sit amet diam ultrices"},
{name: "Duis nec", description: "Proin at dolor at est porta aliquet. Proin viverra imperdiet orci, a ornare tortor"},
{name: "Mauris.", description: "Aenean tristique ante et eros porttitor, ut sodales ipsum pulvinar."},
{name: "Pellentesque", description: "Nam dignissim ipsum a elit fermentum"},
{name: "facilisis augue", description: "Etiam sit amet dolor sed sapien rutrum sodales."},
{name: "erat suscipit", description: "this is an example description"},
]
My schema is defined as below:
const mongoose = require("mongoose");
const schema = new mongoose.Schema({
name: String,
description: String
});
schema.index({ name: "text", description: "text" });
const Items = mongoose.model("Item", schema);

Related

Create nested list items with given depths in JavaScript

I'm trying to make nested list items with the data below:
It creates the right indentation when depths are sorted with -1 +1 but I can't make the perfect indentation. Any help will be appreciated.
const data = [
{depth: 1, title: "Some Title Goes Here - First Title", url: "#some-title-goes-here-first-title-prs7ztig15"},
{depth: 2, title: "Yuck Almost Got it!", url: "#yuck-almost-got-it-qlx0i4727h"},
{depth: 1, title: "Whoops! Something went Wrong", url: "#whoops-something-went-wrong-qoflcur4iw"},
{depth: 1, title: "Don't Worry We Get You Covered", url: "#dont-worry-we-get-you-covered-ug4kxqz4kp"},
{depth: 3, title: "I Hate Writing Titles", url: "#i-hate-writing-titles-jrlw78vulm"},
{depth: 4, title: "Gonna Start to Lorem", url: "#gonna-start-to-lorem-whzh8e3qus"},
{depth: 2, title: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quisquam, voluptate!", url: "#lorem-ipsum-dolor-sit-amet-consectetur-adipisicing-elit-quisquam-voluptate-agxlhkvs8c"},
{depth: 1, title: "Consectetur adipisicing elit. Quo, corporis!", url: "#consectetur-adipisicing-elit-quo-corporis-4xurvdulcn"},
{depth: 1, title: "Dolor sit amet, consectetur adipisicing elit. Fugiat, quae?", url: "#dolor-sit-amet-consectetur-adipisicing-elit-fugiat-quae-txu46oaitk"},
{depth: 2, title: "Adipisicing elit. Dolor, rem.", url: "#adipisicing-elit-dolor-rem-x6coih7o36"},
{depth: 3, title: "Elit. Consequuntur, cum.", url: "#elit-consequuntur-cum-zqyhfglbd4"},
{depth: 4, title: "Ipsum dolor sit amet.", url: "#ipsum-dolor-sit-amet-sz09eh07ma"},
{depth: 2, title: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo, corporis!", url: "#lorem-ipsum-dolor-sit-amet-consectetur-adipisicing-elit-quo-corporis-18g13jn4j5"}]
function getTOCOutput(data) {
if (data.length < 1) return '';
let tocOutput = "<ul>";
let currentDepth = data[0].depth;
let c = data.length;
for (let i = 0; i < c; i++) {
let itemDepth = data[i].depth;
if (currentDepth === itemDepth) {
tocOutput += '<li>' + data[i].title + '';
} else if (currentDepth < itemDepth) {
tocOutput += '<ul><li>' + data[i].title + '';
} else {
tocOutput += '</li>' + '</ul>'.repeat(currentDepth - itemDepth) + '<li>' + data[i].title + '</li>';
}
currentDepth = data[i].depth;
}
tocOutput += "</ul>";
return tocOutput;
}
document.body.innerHTML += getTOCOutput(data);
You can use two while loops inside the for loop in order to account for the depth changes. They repeat until the current depth is right:
function getTOCOutput(data) {
let currentDepth = 0;
let tocOutput = "";
for (let {depth, title, url} of data) {
while (depth > currentDepth) {
tocOutput += "<ul>";
currentDepth++;
}
while (depth < currentDepth) {
tocOutput += "</ul>";
currentDepth--;
}
tocOutput += '<li>' + title + '';
}
return tocOutput;
}
let data = [{depth: 1, title: "Some Title Goes Here - First Title", url: "#some-title-goes-here-first-title-prs7ztig15"},{depth: 2, title: "Yuck Almost Got it!", url: "#yuck-almost-got-it-qlx0i4727h"},{depth: 1, title: "Whoops! Something went Wrong", url: "#whoops-something-went-wrong-qoflcur4iw"},{depth: 1, title: "Don't Worry We Get You Covered", url: "#dont-worry-we-get-you-covered-ug4kxqz4kp"},{depth: 3, title: "I Hate Writing Titles", url: "#i-hate-writing-titles-jrlw78vulm"},{depth: 4, title: "Gonna Start to Lorem", url: "#gonna-start-to-lorem-whzh8e3qus"},{depth: 2, title: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quisquam, voluptate!", url: "#lorem-ipsum-dolor-sit-amet-consectetur-adipisicing-elit-quisquam-voluptate-agxlhkvs8c"},{depth: 1, title: "Consectetur adipisicing elit. Quo, corporis!", url: "#consectetur-adipisicing-elit-quo-corporis-4xurvdulcn"},{depth: 1, title: "Dolor sit amet, consectetur adipisicing elit. Fugiat, quae?", url: "#dolor-sit-amet-consectetur-adipisicing-elit-fugiat-quae-txu46oaitk"},{depth: 2, title: "Adipisicing elit. Dolor, rem.", url: "#adipisicing-elit-dolor-rem-x6coih7o36"},{depth: 3, title: "Elit. Consequuntur, cum.", url: "#elit-consequuntur-cum-zqyhfglbd4"},{depth: 4, title: "Ipsum dolor sit amet.", url: "#ipsum-dolor-sit-amet-sz09eh07ma"},{depth: 2, title: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo, corporis!", url: "#lorem-ipsum-dolor-sit-amet-consectetur-adipisicing-elit-quo-corporis-18g13jn4j5"},];
document.body.insertAdjacentHTML("beforeend", getTOCOutput(data));

filter data on multiple fields

I am trying to build a filter for JSON object at the moment, the json object looks like this,
created_at: null
deleted_at: null
id: 3
listings: Array(3)
0: {id: 3, name: "Learn the basics of the guitar from the anatomy of the guitar to scales, chords", slug: "learn-the-basics-of-the-guitar-from-the-anatomy-of-the-guitar-to-scales-chords", description: "We live in a unique and wonderful time where elect… going to give you a lifetime of awesome rockin’.", booking_details: "undefined", …}
1: {id: 8, name: "Advanced guitar skills with William Topa", slug: "advanced-guitar-skills-with-william-topa", description: "We live in a unique and wonderful time where elect… going to give you a lifetime of awesome rockin’.", booking_details: "Lorem ipsum dolor sit amet, consectetur adipiscing… laboris nisi ut aliquip ex ea commodo consequat.", …}
2: {id: 9, name: "Music production simplified", slug: "music-production-simplified", description: "We live in a unique and wonderful time where elect… going to give you a lifetime of awesome rockin’.", booking_details: "Lorem ipsum dolor sit amet, consectetur adipiscing… laboris nisi ut aliquip ex ea commodo consequat.", …}
length: 3
__proto__: Array(0)
tag: "Music"
updated_at: null
weight: null
This is part of a bigger object, the hierarchy looks like
[{ data, listings }, {data, listings}]
What I am wanting to do, is filter through the listings array and hide any listings that don't have a cost of "0.00"
Here is what i am trying,
<input type="checkbox" v-model="priceFilter" value="0.00" />
data() {
return {
this.priceFilter: []
}
},
computed: {
filteredTags() {
return this.tags.filter(tag => {
tag.listings.filter(listing => "0.00" === listing.cost);
//console.log(this.checkedPrice, listing.cost);
});
},
},
In the above I just trying to return the listings where the cost matches 0.00 with trigger it via the checkbox being checked but even that does not filter as I wish I still see all listings.
Anyone care to offer any advice?

TypeError: Cannot read property 'id' of undefined (REACTJS)

Am still new to Reactjs, thought have tried all I can, but still can't get through this error "TypeError: Cannot read property 'id' of undefined"
please someone help below is my code.
if(this.props.controller === 'location'){
eventData = Object.keys(this.props.heda).map( evKey => {
return Object.keys(evKey).map( post => {
return [...Array(this.props.heda[evKey][post])].map( lol => {
return <Event key= {lol['id']}
descriptions = {lol['description']}
headings = {lol['title']}
id = {lol['id']}
clicked = { ()=> this.viewSelectedEvent(lol['id']) }/>;
}) ;
});
});
}
Error full stacktrace:
here is my data from flask that am trying to loop.Am trying to convert each object into an array, then loop through the array. I also tried to console.log(lol) and i get the data as in the image below
events = [
{
'id': 1,
'title': u'HHGHHMjshjskksjks',
'description': u'Cras justo odio dapibus ac facilisis in egestas eget qua ',
'location':'jkknxjnj',
'category':'party',
'rsvp': False,
'event_owner':1
},
{
'id': 2,
'title': u'khjhjshjsjhdndjdh',
'description': u'jhhnbsbnsbj',
'location':'jhjhsjhjhsjhjdhsd',
'category':'party',
'rsvp': False,
'event_owner':2
},
{
'id': 3,
'title': u'jhjshjsdhjshdjshjsd',
'description': u'Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec elit non mi porta gravida at eget metus.',
'location':'kjkshjhjhjbsnbsd',
'category':'party',
'rsvp': False,
'event_owner':2
},
{
'id': 4,
'title': u'jjhjshjhsjhjshjjhjhd',
'description': u'Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec elit non mi porta gravida at eget metus.',
'location':'kjisisiisdsds',
'category':'party',
'rsvp': False,
'event_owner':2
},
{
'id': 5,
'title': u'uiujsdshuuihuyksjhjs',
'description': u'Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec elit non mi porta gravida at eget metus.',
'location':'sjnsisuis',
'category':'party',
'rsvp': False,
'event_owner':2
},
{
'id': 6,
'title': u'iusijksuiksuhj suyuys jhu ',
'description': u'Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec elit non mi porta gravida at eget metus.',
'location':'isuisiiws',
'category':'party',
'rsvp': False,
'event_owner':2
},
{
'id': 7,
'title': u'jujusi jsuoios jshuysd',
'description': u'Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec elit non mi porta gravida at eget metus.',
'location':'area h',
'category':'party',
'rsvp': False,
'event_owner':2
},
]
With [...Array(this.props.heda[evKey][post])] you create an array which has as the first element the array this.props.heda[evKey][post]).
Maybe you wanted to say [...this.props.heda[evKey][post]] to create a clone of the array?
Because he is not able to find id in this.props.heda[evKey][post] object. So firstly you should console your this.props.heda[evKey][post] object after that I think you will get your actual problem.
Please try below snippet:
this.props.heda.map((evVal, evKey) => {
return evVal.map((postVal, postKey) => {
...
}
}
Now this.props.heda[evKey][postKey] will give you the expected object.

Bootstrap Table filter by string partial

I'm using the Bootstrap-table plugin (http://bootstraptable.wenzhixin.net.cn/documentation/) and I'm trying to filter by tags by utilizing the method filterby but can't figure out how to factor in multiple tags that has to come in as a string, separated by commas.
I created an example to illustrate what I'm attempting to achieve. For simplicity,
Here's the html:
<table id="table">
<thead>
<tr>
<th data-field="date">Date</th>
<th data-field="desc">Description</th>
<th data-field="tags">Tags</th>
</tr>
</thead>
</table>
<br>
<button id="filter-general">General</button>
<button id="filter-rotation">Rotation</button>
<button id="clear">clear</button>
Javascript:
var data = [{
"date": "2016-05-10",
"tags": "General, Research, Rotation",
"desc": "Nunc velit lectus, ornare vitae fringilla eget, vestibulum quis tortor."
},{
"date": "2016-04-22",
"tags": "General",
"desc": "Nunc velit lectus, ornare vitae fringilla eget, vestibulum quis tortor."
},{
"date": "2016-03-23",
"tags": "Research, Rotation",
"desc": "Nunc velit lectus, ornare vitae fringilla eget, vestibulum quis tortor."
},{
"date": "2015-11-01",
"tags": "Rotation",
"desc": "Nunc velit lectus, ornare vitae fringilla eget, vestibulum quis tortor."
},{
"date": "2016-08-15",
"tags": "General, Rotation",
"desc": "Nunc velit lectus, ornare vitae fringilla eget, vestibulum quis tortor."
}];
$(function() {
$table = $('#table');
$table.bootstrapTable({
data: data
});
$('#clear').click(function() {
$table.bootstrapTable('filterBy', {});
});
$('#filter-general').click(function() {
$table.bootstrapTable('filterBy', {
tags: "General"
});
});
$('#filter-rotation').click(function() {
$table.bootstrapTable('filterBy', {
tags: "Rotation"
});
});
});
http://jsfiddle.net/zqxwr3uL/6/
Edit: Either by filterby method or from one of the filter extensions.
I think you are out of luck using the filterBy fuction. From the source code (https://github.com/wenzhixin/bootstrap-table/blob/develop/src/bootstrap-table.js):
var f = $.isEmptyObject(this.filterColumns) ? null : this.filterColumns;
// Check filter
this.data = f ? $.grep(this.options.data, function (item, i) {
for (var key in f) {
if ($.isArray(f[key]) && $.inArray(item[key], f[key]) === -1 ||
item[key] !== f[key]) {
return false;
}
}
return true;
}) : this.options.data;
where item[key] is your cell value and f[key] is your filter string. $.inArray is looking for the complete text of the cell in your filter strings.
i know, old session but just change check filter part to this:
for (var key in f) {
if (Array.isArray(f[key]) && !f[key].includes(item[key])) {
return false;
}
if(!Array.isArray(f[key]) ){
if(item[key].search(f[key])==-1){
return false
}
}
}

Angular repeating images

New to angular and developing a simple page just to learn the inner workings. What I have is a div that display name price and description along with a button and a full image. What I'm trying to do is underneath that full image display 2-3 additional images. The problem is the same full image is displaying again and none of the additional images are displaying.
Here is the angular
(function () {
var app = angular.module('gemStore', []);
app.controller('StoreController', function () {
this.products = gems;
});
var gems = [
{
name: 'Defmei',
price: 2.95,
description: 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ',
canPurchase: true,
soldOut: false,
images: [
{
image: "Images/image1.jpg",
image: "Images/image2.jpg",
image: "Images/image3.jpg"
}
]
},
{
name: 'Sijoi',
price: 5.95,
description: 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ',
canPurchase: true,
soldOut: true,
images: [
{
image: "Images/image4.jpg",
image: "Images/image3.jpg",
image: "Images/image2.jpg"
}
]
}
]
})();
Here is the HTML
<body data-ng-controller="StoreController as store" >
<div class="display" data-ng-repeat="product in store.products">
<h1>{{product.name}}</h1>
<h2>{{product.price | currency}}</h2>
<p> {{product.description}} </p>
<img class="imageStyles" data-ng-src="{{product.images[0].image}}"/>
<br />
<div data-ng-repeat="image in product.images">
<img data-ng-src="{{image.image}}" class="thumbs" />
</div>
<button data-ng-show="product.canPurchase">Add to cart</button>
</div>
</body>
That image object seems "broken", you're practically redefining the image attribute 3 times.
In javascript, objects have a syntax like { attribName1: attValue1, attribName2: attValue2 ...}
What you're creating here:
images: [
{
image: "Images/image1.jpg",
image: "Images/image2.jpg",
image: "Images/image3.jpg"
}
]
Is an array with 1 item, which is an object, with 1 property, "image", with a value of... "Images/image3.jpg" maybe (or whatever, I wouldn't be surprised if double-defining attributes like this was in fact undefined behaviour).
What you probably want instead is either an array with 3 elements, or an object with 3 distinct attributes, ie:
images: [
{
"image1": "Images/image1.jpg",
"image2": "Images/image2.jpg",
"image3": "Images/image3.jpg"
}
]
You can iterate through array members and object attributes too with ng-repeat, but you have to change your code accordingly.
Your images array only has one item in it with image defined three times. Change it like the following so that there are three separate items and it should work.
images: [
{image: "Images/image4.jpg"},
{image: "Images/image3.jpg"},
{image: "Images/image2.jpg"}
]

Categories