Lodash sort incorrect with Alphanumberic? - lodash

I'm using lodash to sort Array.
Ex:
const arr = [ { name: 'Card 2' }, { name: 'Card 1' }, { name: 'Card 10' }]
Sort:
lodash.orderBy(arr, ['name'], ['asc'])
Result:
[{ name: 'Card 1' }, { name: 'Card 10' }, { name: 'Card 2' }]
How I can resolve it?
My expect the result should be:
[ { name: 'Card 1' }, { name: 'Card 2' }, { name: 'Card 10' }]

It is correct. You are sorting lexicographically. Just like the "aardvark" goes after "a" and before "b", so does "10" go after "1" but before "2". If you want to sort it numerically, you would need to extract the number.
Here, I split each array into alphabetic and numeric portions, then pad the numeric portions with zeroes so that they can be compared like strings (e.g. "Card 0000000000000010"):
const arr = [ { name: 'Card 2' }, { name: 'Card 1' }, { name: 'Card 10' }, { name: 'Document 1' }]
const sortedArr = _.sortBy(arr, [function(o) {
const split = o.name.split(/\b(\d+)\b/);
for (let i = 1; i < split.length; i += 2) {
split[i] = split[i].padStart(16, '0');
}
return split.join('');
}]);
console.log(sortedArr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

If you expect your items to have numbers only at the end, then you can define your own sorting comparator and perform the following logic:
Take any part of the item before from the beginning until any number from each item and compare them alphabetically.
If equal, then compare the numbers from the end numerically.
To do this, you can just pass two iteratees to orderBy:
You can easily achieve that with the /^[^\d]*/ regex.
That can be done using the /\d*$/ regex and converting to a number.
const arr = [ { name: 'Card 2' }, { name: 'Card 1' }, { name: 'Card 10' }, { name: 'Alpha 2' }, { name: 'Alpha 1' }, { name: 'Alpha 10' }, { name: 'Beta 2' }, { name: 'Beta 1' }, { name: 'Beta' }, { name: '2' }, { name: '1' }, { name: '10' },{ name: 'Gamma' }, { name: 'Delta' },]
const extractString = item => item.name.match(/^[^\d]*/)[0];
const extractNumber = item => Number(item.name.match(/\d*$/)[0]);
const sorted = _.orderBy(arr, [extractString, extractNumber], ['asc']);
console.log(sorted);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>

Related

Invalid property value: API create Mutation Sanity.io Reference is string - how to define as reference?

i am building a ecommerce site.
I have trouble adding orderItems to the Array in the Order-Document.
As you can see i am trying to reference the customer-Document and Product-Dokument in my orderItem. i am Posting in an array of objects that looks like:
[
{
productId: '5b79b3f8-6ef8-4c6d-bd85-5dcb14fb836d',
kundenId: 'c3777230-74cd-411b-a455-7fa905c90957',
quant: 1,
name: 'Position 1'
}
]
Can someone help me how i get sanity to understand the strings as _ref ?
My schemas are as follows:
export default {
title: 'Order Item',
name: 'orderItem',
type: 'object',
fields: [
{
title: 'Name',
name: 'name',
type: 'string',
},
{
name: 'kundenId',
title: 'Customer',
type: 'reference',
to: [{ type: 'customer' }],
options: {
disableNew: true,
},
},
{
name: 'productId',
title: 'Product',
type: 'reference',
to: [{ type: 'product' }],
options: {
disableNew: true,
},
},
{
title: 'Quantity',
name: 'quant',
type: 'number',
},
{
title: 'Price',
name: 'price',
type: 'number',
},
],
};
and:
export default {
name: 'order',
title: 'Order',
type: 'document',
fields: [
{
name: 'user',
title: 'User',
type: 'reference',
to: [{ type: 'user' }],
options: {
disableNew: true,
},
},
{
name: 'userName',
title: 'User Name',
type: 'string',
},
{
title: 'Order Items',
name: 'orderItems',
type: 'array',
of: [
{
title: 'Order Item',
type: 'orderItem',
},
],
},
{
title: 'CreatedAt',
name: 'createdAt',
type: 'datetime',
},
],
};
so i solved this by using JSON.parse like so:
productId: JSON.parse(`{"_ref":"${artikel._id}"}`),
Good luck to everyone with the same issue.

Loadash filter need to get exact match

When trying to filter array using Lodash, i am getting all the element of that array. Need to get the specific array only. Please find my coding so far
var sizeList = [{
id: 1,
title: "Test1",
type: [{
name: "1.1",
present: false
}, {
name: "1.2",
present: true
}, {
name: "1.3",
present: false
}]
}, {
id: 2,
title: "Test2",
type: [{
name: "2.1",
present: false
}, {
name: "2.2",
present: true
}, {
name: "2.3",
present: false
}]
}, {
id: 3,
title: "Test3",
type: [{
name: "3.1",
present: false
}, {
name: "3.2",
present: true
}, {
name: "3.3",
present: true
}]
}],
result = _.filter(sizeList, {
type: [{
name: '3.3'
}]
});
console.log(result);
My problem is, when i filter with name:3.3 i am getting all the element in Test3 array including 3.1, 3.2 and 3.3. I need to only 3.3. Can anyone please help.
You can map the items after filtering by type, and filter the type array as well:
var sizeList = [{"id":1,"title":"Test1","type":[{"name":"1.1","present":false},{"name":"1.2","present":true},{"name":"1.3","present":false}]},{"id":2,"title":"Test2","type":[{"name":"2.1","present":false},{"name":"2.2","present":true},{"name":"2.3","present":false}]},{"id":3,"title":"Test3","type":[{"name":"3.1","present":false},{"name":"3.2","present":true},{"name":"3.3","present":true}]}];
var result = _(sizeList)
.filter({
type: [{ name: '3.3' }]
})
.map(({ type, ...o }) => ({
...o,
type: _.filter(type, { name: '3.3' })
}))
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Filter query result by field value inside array of objects [Sanity.io & GROQ]

I'm trying to find a product variant inside my list of products(on sanity.io using GROQ), to do so, I have the sku of the variant that I want.
The query I'm using is
*[_type == "product" && variants[].sku.current =="kit-kat-wasabi-5" ]
But this query returns an empty array. I'm sure that the sku is correct because if I leave the filter aside, and fetch all I can find it.
I tried replacing the "==" with match, but the result is the same.
my schemas are
procuct
export default {
name: 'product',
title: 'Product',
type: 'document',
fields: [
{
name: 'title',
title: 'Inner Title',
type: 'string'
},
{
title: 'SKU',
name: 'sku',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
validation: Rule => Rule.required()
},
{
name: 'titleWebsite',
title: 'Title Website',
type: 'localeString'
},
{
name: 'active',
title: 'Active',
type: 'boolean'
},
{
name: 'mainImage',
title: 'Imagem',
type:"image"
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96
}
},
{
title: 'Base Price',
name: 'basePrice',
type: 'localeCurrency'
},
{
title: 'Quantidade',
name: 'qty',
type: 'number'
},
/* {
title: 'Default variant',
name: 'defaultProductVariant',
type: 'productVariant'
},*/
{
title: 'Variants',
name: 'variants',
type: 'array',
of: [
{
title: 'Variant',
type: 'productVariant'
}
]
},
{
title: 'Tags',
name: 'tags',
type: 'array',
of: [
{
type: 'string'
}
],
options: {
layout: 'tags'
}
},
{
name: 'vendor',
title: 'Vendor',
type: 'reference',
to: {type: 'vendor'}
},
{
name: 'blurb',
title: 'Blurb',
type: 'localeString'
},
{
name: 'categories',
title: 'Categories',
type: 'array',
of: [
{
type: 'reference',
to: {type: 'category'}
}
]
},
{
name: 'body',
title: 'Body',
type: 'localeBlockContent'
}
],
preview: {
select: {
title: 'title',
manufactor: 'manufactor.title',
media: 'mainImage'
}
}
}
And productVariant
export default {
title: 'Product variant',
name: 'productVariant',
type: 'object',
fields: [
{
title: 'Title',
name: 'title',
type: 'string'
},
{
title: 'Title Website',
name: 'titleWebsite',
type: 'localeString'
},
{
title: 'Weight in grams',
name: 'grams',
type: 'number'
},
{
title: 'Price',
name: 'price',
type: 'localeCurrency'
},
{
title: 'SKU',
name: 'sku',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
validation: Rule => Rule.required()
},
{
title: 'Taxable',
name: 'taxable',
type: 'boolean'
},
{
name: 'blurb',
title: 'Blurb',
type: 'localeString'
},
{
name: 'images',
title: 'Images',
type: 'array',
of: [
{
type: 'image',
options: {
hotspot: true
}
}
]
},
{
title: 'Quantidade',
name: 'qty',
type: 'number'
},
{
title: 'Bar code',
name: 'barcode',
type: 'barcode'
}
]
}
This is a known bug in GROQ when traversing arrays. This will introduce breaking changes if it were to be fixed in GROQ v1. It will therefore be fixed in GROQ v2.
Here is a bug report explaining the issue: https://github.com/sanity-io/sanity/issues/1557. You can show your interest in this problem here.
There's a working draft for version two here: https://github.com/sanity-io/groq.
Regarding your schema, I would consider to change the type of the sku field to be something else, for example a string, and create a new field for the slug which has its source property set to the SKU to be automatically be generated by that field. Documentation for that can be found here: https://www.sanity.io/docs/slug-type.

show comments like facebook with express

I have the next Schema:
var eventSchema = mongoose.Schema({
title: 'string',
propietary_id: 'String',
comments : [{
text: 'string',
user: { type : mongoose.Schema.Types.ObjectId, ref : 'users' },
createdAt: {type: Date, default: Date.now }
}]
});
my query:
Event.find().populate('comments.user').exec(function(err, doc){
console.log(err);
console.log(doc);
});
it's possible return object with events information, 2 comments and total number of comments (like facebook) ?
I would do it like this:
var NBR_OF_COMMENTS = 2;
Event.find().populate('comments.user').exec(function(err, event){
var comments = event.comments;
var totalNbrOfComments = comments.length;
comments.splice(NBR_OF_COMMENTS, totalNbrOfComments - NBR_OF_COMMENTS);
event.comments = {
count: comments.length,
total: totalNbrOfComments,
items: comments,
};
res.json(event);
});
For example, this should return the following:
{
title: 'test',
property_id: '123',
comments: {
count: 2,
total: 5,
items: [
{
text: 'comment 1',
...
},
{
text: 'comment 2',
...
},
],
}
}

How to map hierarchical Json to ItemFileWriteStore?

I have Json data that has children elements. I need to bind the store to an editable grid and have the edits populated to the store.
The data tree does get populated into the ItemFileWriteStore. The datagrid displays only the parent data and none of the children data.
SAMPLE.TXT
{
"items": [
{
"profileId": "1",
"profileName": "ABC",
"profileType": "EmailProfile",
"profilePreferences": [
{
"profilePreferenceId": "1",
"displayText": "Bob",
"address": "primary#some.com"
},
{
"profilePreferenceId": "2",
"displayText": "Sally",
"address": "secondary#some.com"
},
{
"profilePreferenceId": "3",
"displayText": "Joe",
"address": "alternate#some.com"
}
]
}
]
}
javascript
var sampleLayout = [
[
{ field: 'profileName', name: 'profileName', width: '100px' },
{ field: 'profilePreferences.displayText', name: 'displayText', width: '100px' },
{ field: 'profilePreferences.address', name: 'address', width: '100px' }
]];
function populateGrid() {
var url = "sample.txt"; //Will be replaced with endpoint URL
dojo.xhrGet({
handleAs: 'json',
url: url,
error: function (e) {
alert("Error: " + e.message);
},
load: showJsonData
});
}
function showJsonData(response, ioArgs) {
var profileStore = new dojo.data.ItemFileWriteStore({
data: {
items: response.items
}
});
var sampleGrid = dijit.byId("sampleGrid");
sampleGrid.store = profileStore;
sampleGrid.startup();
}
you need to be using dojox.grid.TreeGrid or 'fake' the JSON to present every even row with a blank profileName. Two samples follows, one for TreeGrid another on DataGrid - not tested in working environment though.
Given Hierachial JSON:
{
identifier: 'id' // a good custom to make an id pr item, note spaces and odd chars are invalid
items: [{
id: '1',
profileName: 'Admin',
profilePreferences: [
{ id: '1_1', displayText: 'John Doe', address: 'Big Apple' }
{ id: '1_2', displayText: 'Jane Doe', address: 'Hollywood' }
]
}, {
id: '2',
profileName: 'Visitor',
profilePreferences: [
{ id: '2_1', displayText: 'Foo', address: 'Texas' }
{ id: '2_2', displayText: 'Bar', address: 'Indiana' }
]
}]
}
TreeGrid Structure:
{
cells: [
[
{ field: "profileName", name: "profileName", width: "100px" },
{ field: "profilePreferences",
children: [
{ field: "displayText" name: "displayText", width: "100px" },
{ field: "address" name: "address", width: "100px" }
]
]
]
}
reference: dojo docs
Given flattened 'fake-children' JSON:
{
identifier: 'id' // a good custom to make an id pr item, note spaces and odd chars are invalid
items: [{
id: '1',
profileName: 'Admin', preferenceText: '', preferenceAddr: ''
}, {
id: '2',
profileName: '', preferenceText: 'John', preferenceAddr: 'NY'
}, {
id: '3',
profileName: 'Visitor', preferenceText: '', preferenceAddr: ''
}, {
id: '4', // Not with '.' dot seperator like so
profileName: '', preference.Text: 'Jane Doe', preference.Addr: 'Hollywood'
} ]
DataGrid structure:
[[
{'name': 'Profilename', 'field': 'profileName', 'width': '100px'},
{'name': 'User name', 'field': 'preferenceText', 'width': '100px'},
{'name': 'Address', 'field': 'preferenceAddr', 'width': '200px'}
]]
reference dojo docs