Sort Based on Property - sails.js

How can I do something like:
sort('object.property')
(object is defined as type 'json' in the model)
with Waterline?
Note that I am using the latest stable build 0.9.~ which does not have associations yet.

A quick test showed the sails-mongo adapter allows sorting of JSON attributes out of the box (it is transparently reached to the mongo database).
First I created a blank controller and model using:
sails generate foo
Then I defined a data property with type json on my model:
module.exports = {
attributes: {
data: 'json'
}
};
I created several objects by doing a HTTP POST with data like this (I increased the sort value):
{
"data": {
"sort": 1
}
}
Afterwards I fetched my collection using this GET request:
http://localhost:1337/foo?sort=data.sort+desc
which will internally result in a call like
Foo.find().sort('data.sort desc').exec(callback);
The server response is now sorted by the given property:
[
{
"data": {
"sort": 3
},
"createdAt": "2014-04-13T09:35:49.734Z",
"updatedAt": "2014-04-13T09:35:49.734Z",
"id": "534a5a7553f1e98e09d1d86b"
},
{
"data": {
"sort": 2
},
"createdAt": "2014-04-13T09:35:45.814Z",
"updatedAt": "2014-04-13T09:35:45.814Z",
"id": "534a5a7153f1e98e09d1d86a"
},
{
"data": {
"sort": 1
},
"createdAt": "2014-04-13T09:35:41.958Z",
"updatedAt": "2014-04-13T09:35:41.958Z",
"id": "534a5a6d53f1e98e09d1d869"
}
]

Related

Loopback 3 query by Property of a embedded model

I'm using loopback 3 to build a backend with mongoDB.
So i have 2 models: Object and Attachment. Object have a relation Embeds2Many to Attachment.
Objects look like that in mongoDB
[
{
"fieldA": "valueA1",
"attachments": [
{
"id": 1,
"url": "abc.com/image1"
},
{
"id": 2,
"url": "abc.com/image2"
}
]
},
{
"fieldA": "valueA2",
"attachments": [
{
"id": 4,
"url": "abc.com/image4"
},
{
"id": 5,
"url": "abc.com/image5"
}
]
}
]
The question is: how can i get Objects with attachments.id=4 over the RestAPI?
I have try with the where and include filter. But it didn't work. It look like, that this function is not implemented in loopback3, right?
I have found the solution. It only works on Mongodb, Cloudant and Memory database.
{
"filter": {
"where": {
"attachments.id": 4
}
}
}

How to filter OData collection where attribute does not exist?

I have an OData collection where the data looks like this:
{
"#odata.context": "http://localhost:5488/odata/$metadata#folders",
"value": [
{
"name": "samples",
"_id": "79a91bc9-9083-4442-ac8d-ad30777ac8c8",
"creationDate": "2019-08-05T04:39:00.670Z",
"modificationDate": "2019-08-05T04:39:00.670Z",
"shortid": "18xQnNv"
},
{
"name": "Population",
"folder": {
"shortid": "18xQnNv"
},
"_id": "7406269b-669c-41ce-92f3-f540792df07e",
"creationDate": "2019-08-05T04:39:00.750Z",
"modificationDate": "2019-08-05T04:39:00.750Z",
"shortid": "0ppeLV"
},
{
"name": "Invoice",
"folder": {
"shortid": "18xQnNv"
},
"_id": "525aff6a-6b10-4ad6-93ce-e9c753e8ade0",
"creationDate": "2019-08-05T04:39:00.790Z",
"modificationDate": "2019-08-05T04:39:00.790Z",
"shortid": "G3i2B3"
},
{
"name": "Default",
"_id": "58daf5aa-1f13-4ff9-be1f-8cb11a812485",
"creationDate": "2019-08-07T22:56:45.160Z",
"modificationDate": "2019-08-07T22:56:45.160Z",
"shortid": "Sm8LpmP"
}
]
}
I want to exclude the objects which have the attribute "folder". I've tried using a GET request: http://localhost:5488/odata/folders?$filter=folder eq null with no luck. Is this even possible and is there a way to filter my request like this?
You might be able to use the all lambda operator to accomplish this. The operator all will always return true on empty collections. So if you make a condition that no folder attribute that actually exists will ever evaluate to true on, then the result should be a filter of only those objects that have an empty attribute.
This is just a theory. You'll need to test, but it would maybe look something like this on your sample.
http://localhost:5488/odata/folders?$filter=folder/all(f:f/shortid eq 'xxxxxx')
You didn't mention the version of OData your working with but lambda expressions are at least V4 and later. Possibly earlier, not sure.

Meteor MongoDB - cant insert _id with _id from API call

I am trying to call the TwitchAPI and insert some of the returned data into MongoDB. However, every time I get this error: Error: Meteor requires document _id fields to be non-empty strings or ObjectIDs.
The Twitch API response for a single stream/channel looks like this:
{
"streams": [
{
"_id": 11220687552,
"game": "League of Legends",
"viewers": 11661,
"created_at": "2014-09-30T01:10:36Z",
"_links": {
"self": "http://api.twitch.tv/kraken/streams/mushisgosu"
},
"preview": {
"small": "http://static-cdn.jtvnw.net/previews-ttv/live_user_mushisgosu-80x50.jpg",
"medium": "http://static-cdn.jtvnw.net/previews-ttv/live_user_mushisgosu-320x200.jpg",
"large": "http://static-cdn.jtvnw.net/previews-ttv/live_user_mushisgosu-640x400.jpg",
"template": "http://static-cdn.jtvnw.net/previews-ttv/live_user_mushisgosu-{width}x{height}.jpg"
},
"channel": {
"_links": {
"self": "https://api.twitch.tv/kraken/channels/mushisgosu",
"follows": "https://api.twitch.tv/kraken/channels/mushisgosu/follows",
"commercial": "https://api.twitch.tv/kraken/channels/mushisgosu/commercial",
"stream_key": "https://api.twitch.tv/kraken/channels/mushisgosu/stream_key",
"chat": "https://api.twitch.tv/kraken/chat/mushisgosu",
"features": "https://api.twitch.tv/kraken/channels/mushisgosu/features",
"subscriptions": "https://api.twitch.tv/kraken/channels/mushisgosu/subscriptions",
"editors": "https://api.twitch.tv/kraken/channels/mushisgosu/editors",
"videos": "https://api.twitch.tv/kraken/channels/mushisgosu/videos",
"teams": "https://api.twitch.tv/kraken/channels/mushisgosu/teams"
},
"background": null,
"banner": "http://static-cdn.jtvnw.net/jtv_user_pictures/mushisgosu-channel_header_image-c5c08cce281b7be3-640x125.jpeg",
"display_name": "MushIsGosu",
"game": "League of Legends",
"logo": "http://static-cdn.jtvnw.net/jtv_user_pictures/mushisgosu-profile_image-b1c8bb5fd700025e-300x300.png",
"mature": false,
"status": "CLG hi im Gosu - Challenger AD - Smurfing Master!",
"partner": true,
"url": "http://www.twitch.tv/mushisgosu",
"video_banner": "http://static-cdn.jtvnw.net/jtv_user_pictures/mushisgosu-channel_offline_image-7e3401b20cb5d739-640x360.png",
"_id": 41939266,
"name": "mushisgosu",
"created_at": "2013-03-31T21:12:14Z",
"updated_at": "2014-09-30T03:08:55Z",
"abuse_reported": null,
"delay": 60,
"followers": 318914,
"profile_banner": null,
"profile_banner_background_color": null,
"views": 25963780,
"language": "en-us"
}
}
],
"_total": 8477,
"_links": {
"self": "https://api.twitch.tv/kraken/streams?limit=1&offset=0",
"next": "https://api.twitch.tv/kraken/streams?limit=1&offset=1",
"featured": "https://api.twitch.tv/kraken/streams/featured",
"summary": "https://api.twitch.tv/kraken/streams/summary",
"followed": "https://api.twitch.tv/kraken/streams/followed"
}
}
The part of my server method that tries to insert the data
Meteor.call('getStreams', function(err, res) {
var data = res.data.streams;
console.log(data);
data.forEach(function(item) {
console.log(item._id);
Streams.insert({
_id: item._id,
title: item.channel.status,
author: item.channel.display_name,
url: item.url
});
});
});
getStreams simple defines the url to call and sets some variable. As you can see I am console logging the expected _id so I know it is returning a valid string but I am still getting the error. Currently, when I make the call I return 100 streams at a time and iterate through them to save the 4 fields above. Ideally, I would like to save each stream object as its own entry in the DB but all my attempts to do that have resulted in the same error and I also read somewhere that the version on "miniMongo" bundled with Meteor does not support inserting an array of objects in bulk...I also have read that miniMong does not support Collection.save() so sadly I think it will be more later to update the contents of each _id with the latest API call info since I cant just use .save to update and insert in the same statement.
I am not sure if it has any impact but I did try setting autoIndexId to false when creating the collection and it doesn't seem to matter:
Streams = new Meteor.Collection('streams', {autoIndexId: false});
Any insight is appreciated.
The problem is that the twitch _id is NOT a String, it appears to be a Number (I can tell by the output of your JSON : the number is not surrounded by quotes).
What I'd do is let Meteor generate its own internal Mongo IDs and store the twitch _id as a separate property instead.
Streams.insert({
twitchId: item._id,
title: item.channel.status,
author: item.channel.display_name,
url: item.url
});
You will have to retrieve the streams by twitchId instead of _id, but it's hardly a problem, right ?

How to update the Embedded Data which is inside of another Embedded Data?

I have document like below in MongoDB:
{
"_id": "test",
"tasks": [
{
"Name": "Task1",
"Parameter": [
{
"Name": "para1",
"Type": "String",
"Value": "*****"
},
{
"Name": "para2",
"Type": "String",
"Value": "*****"
}
]
},
{
"Name": "Task2",
"Parameter": [
{
"Name": "para1",
"Type": "String",
"Value": "*****"
},
{
"Name": "para2",
"Type": "String",
"Value": "*****"
}
]
}
]
}
There is Embedded Data Structure (Parameter) inside of another Embedded Data Structure (Tasks). Now I want to update the para1 in Task1's Parameter.
I have tried many ways but I can only use query tasks.Parameter.name to find the para1 but cannot update it. the example in the doc are using .$. to update the value in a Embedded Data Structure but it doesn't work in my case.
Anyone have any ideas ?
MongoDB currently only supports the positional operator once, and only for the top level array. There is a ticket SERVER-831 to change this behavior for your use case. You can follow the issue there and up vote it.
However, you might be able to change your approach to accomplish what you want to do. One way is to change your schema. Collapse the tasks name into the array so the document looks like this:
{
_id:test,
tasks:
[
{
Task:1
Name:para1,
Type:String,
Value:*****
},
{
Task:1
Name:para2,
Type:String,
Value:*****
},
{
Task:2
Name:para1,
Type:String,
Value:*****
},
{
Task:2
Name:para2,
Type:String,
Value:*****
}
]
}
Another approach that may work for you is to use $pull and $push. For instance something like this to replace a task (this assumes that tasks.Parameter.Name is unique to an array of Parameters):
db.test2.update({$and: [{"tasks.Name": "Task3"}, {"tasks.Parameter.Name":"para1"}]}, {$pull: {"tasks.$.Parameter": {"Name": "para1"}}})
db.test2.update({"tasks.Name": "Task3"}, {$push: {"tasks.$.Parameter": {"Name": "para3", Type: "String", Value: 1}}})
With this solution you need to be careful with regard to concurrency, as there will be a brief moment where the document doesn't exist.

Remove entry in an array of a MongoDB document

Say I have a document that looks something like this:
{
"_id": ObjectId("50b6a7416cb035b629000001"),
"businesses": [{
"name": "Biz1",
"id": ObjectId("50b6bc953e47dc923e000001")
}, {
"name": "Biz2",
"id": ObjectId("50b6ccebae0513bf52000001")
}, {
"name": "Biz3",
"id": ObjectId("50b6d015c58b414156000001")
}, {
"name": "Biz4",
"id": ObjectId("50b6d0c8a4cdd5e356000001")
}]
}
I want to remove
{
"name": "Biz3",
"id": ObjectId("50b6d015c58b414156000001")
}
from the array of businesses. I tried this (using business name instead of id for clarity):
db.users.update({'businesses.name':'Biz3'},{$pull:{'businesses.name':'Biz3'}})
but of course it didn't work. I know that the query part is correct because I get the document back when I do this:
db.users.find({'businesses.name' : 'Biz3'})
So the problem is with the update part.
Just ran a quick lil test and this works
I think trying db.users.update({'businesses.name':'Biz3'},{$pull:{'businesses':{'name':'Biz3'}}}) should do it