Target First Object in Array with Passed MongoDB Query - javascript

I am using this mongoDB query passed via a POST request to return a subset of data:
body: any = {"services.history": { "$elemMatch": { "status": "orientation", "enrolled" : true } }};
This is working as expected. However, we're changing our implementation to target a status and a check that it's the first item in the "history" array. How could I accomplish this with a modification of the above query?
I thought this might work, but no go:
body: any = {"services.history[0]": { "$elemMatch": { "status": "orientation", "enrolled" : true } }};
I also tried dot notation, still no go:
body: any = {"services.history.0": { "$elemMatch": { "status": "orientation", "enrolled" : true } }};
How can I target just the first item in the array with this kind of query in a POST request? In other words, I only want it to return true if the elemMatch matches AND it's the first item in the "history" array. I only need to run this check on the first object on the history array, since I know that'll be the latest (most relevant) data object in the backend array.
The data I'm querying looks like this:
"history": [
{
"status": "oritentation",
"endDate": "2012-09-26T06:00:00.000Z",
"startDate": "2011-03-26T06:00:00.000Z",
"_id": "1259c4d250502sa434788",
"enrolled": true,
}
]

If you do not have additional fields inside the subdocuments of your array you can do this:
body: any = {"services.history.0": { "status": "orientation", "enrolled" : true } }
If you do have additional fields you can do this instead:
body: any = { "services.history.0.status": "orientation", "services.history.0.enrolled": true }

Related

Supabase JSON query JavaScript

Im trying to fetch single entry from my table that contains and JSONB array of objects. Can I match somehow that array to find the desired result?
[
{
"chats": [
{
"id": 56789,
},
{
"id": 66753,
},
],
"id": 999
},
{
"chats": [
{
"id": 43532,
}
],
"id": 999
}
]
I would like to get the object that matches id 999 and contains in chats -> id: 66753
Tried few approaches but none worked.
I though something link this will work.But no success
let { data, error } = await supabase
.from('xyz')
.select('*')
.eq('id', 999)
.contains('chats', {id: 66753})
Can it be done ?
I believe you need to use the ->> operator when querying JSONB data from supabase as noted here in the docs.
So, if your column with the array of objects is titled jsonb, something to the effect of:
let { data, error } = await supabase
.from('xyz')
.select('*')
.eq('id:jsonb->>id', 999)
.contains('chats:jsonb->>chats', ['chats->id: 66753'])
More info can be found on PostgREST docs here

Moongoose update subdocument array object

I want to update one object of an subdoc array with findByIdAndUpdate by parent id and subdoc object id. When executing this code, I got this error:
The positional operator did not find the match needed from the query.
When I use updateOne with filter parameter, it works. But I would like to get the updated document to return as json for rest api.
Is there any way to get the updated document?
My Code:
Subject.findByIdAndUpdate(
{ _id: req.params.subjectId, "bookmarks._id": req.params.bookmarkId },
{
$set: {
"bookmarks.$.uri": req.body.uri
}
},
{ new: true }
)
Schema:
{
"_id": "5e7fbfc05ff6be1446b51af7",
"user_id": "5e7e68c3fd5e9404ce6a14a3",
"title": "Hello World",
"date": "2020-03-28T21:21:04.434Z",
"bookmarks": [
{
"date": "2020-03-28T21:21:20.806Z",
"_id": "5e7fbfd05ff6be1446b51afa",
"uri": "lorem ipsum"
},
{
"date": "2020-03-28T21:21:21.433Z",
"_id": "5e7fbfd15ff6be1446b51afb",
"uri": "lorem ipsum"
}
]
}
You should be using .findOneAndUpdate() :
As your req.params.subjectId and req.params.bookmarkId are strings & respective fields in your DB will be of type ObjectId() - So convert strings to ObjectId() using below code :
const mongoose = require('mongoose');
const _id = mongoose.Types.ObjectId(req.params.subjectId);
const bookmarkId = mongoose.Types.ObjectId(req.params.bookmarkId);
Subject.findOneAndUpdate(
{ _id: _id, "bookmarks._id": bookmarkId },
{
$set: {
"bookmarks.$.uri": 'new new'
}
},
{ new: true }
)
Your issue should be mongoose's .findByIdAndUpdate() does takes in just one string value & internally converts it into {_id : ObjectId(req.params.subjectId)} to use .findOneAndUpdate(), it's just kind of wrapper.

Deep picking using Underscore.JS

I am trying to use underscoreJs to manipulate a JavaScript object and having problems doing so.
Here is my example
var data = {
"label": "SomeName",
"parent": [{
"id": "parentId",
"resources": [{
"name": "ID1NAME",
"calls": [
"user_get", "user2_post", "user3_delete"
]
}, {
"name": "ID2",
"calls": [
"employee1_get", "employee2_delete", "employee3_update"
]
}]
}]
};
var res = _(data).chain().
pluck('parent').
flatten().
findWhere(function(item){
item === "user_get"
}).
value();
console.log(res);
Using an element which is a part of data.parent.calls[] (example : "user_get") I would like to extract its parent object, i.e. data.parent[0].
I tried above but always get undefined. I appreciate any help on this.
One of the problems you're having is your use of _.pluck. If you execute _.pluck over an object, it'll go over the keys of the object trying to retrieve the property you specified as the second argument (in this case, 'parent'). 'label' is a string and 'parent' is an array so thus the array that you get as a result is [undefined, undefined]. The rest will then go wrong.
One solution could be as follows:
function findCallIndexInParent(call, parent) {
return _.chain(parent)
.pluck('resources')
.flatten()
.findIndex(function (obj) {
return _.contains(obj.calls, call);
})
.value();
}
function findCall(call, data) {
var parent = data.parent;
return parent[findCallIndexInParent(call, parent)];
}
console.log(findCall('user_get', data));
findCall is just a convenient method that will pass the parent property of data to findCallIndexInParent (that will retrieve the index where call is) and return the desired object with the parent array.
Lodash (a fork of underscore) provides a method to get the property of an object that would have come really handy in here (sadly, underscore doesn't have it).
The explanation of findCallIndexInParent is as follows:
Chain the parent list
pluck the resources array
As pluck maps, it returns a list of lists so a flatten is needed.
Find the index of the element which calls contains call
Return the value (the index) of the object that contains call within parent.
Here's the fiddle. Hope it helps.
This would seem to do the trick.
function findByCall(data, call) {
return _.find(data.parent, function(parent) { //From data.parent list, find an item that
return _.some(parent.resources, function(resource) {//has such parent.resource that it
return _.includes(resource.calls, call); //includes the searched resource.calls item
});
});
}
//Test
var data = {
"label": "SomeName",
"parent": [{
"id": "parentId",
"resources": [{
"name": "ID1NAME",
"calls": [
"user_get", "user2_post", "user3_delete"
]
}, {
"name": "ID2",
"calls": [
"employee1_get", "employee2_delete", "employee3_update"
]
}]
}]
};
console.log(findByCall(data, 'user_get'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
If I understand correctly, you want to get the index of the element in the parent array which has any resource with the specified call.
data = {
"label": "SomeName",
"parent": [{
"id": "parentId",
"resources": [{
"name": "ID1NAME",
"calls": [
"user_get", "user2_post", "user3_delete"
]
}, {
"name": "ID2",
"calls": [
"employee1_get", "employee2_delete", "employee3_update"
]
}]
}]
}
// find the index of a parent
const index = _.findIndex(data.parent, parent =>
// that has any (some) resources
_.some(parent.resources, resource =>
// that contains 'user_get' call in its calls list
_.contains(resource.calls, 'user_get')
)
)
console.log(index) // 0
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
If you want to find the actual parent object, use find instead of findIndex
If you want to find all parent objects matching this call, use filter instead of findIndex

Backbone .fetch() adds one too many models

I am using backbone's fetch method to retrieve a set of JSON from the server. Inside the fetch call, I have a success callback that correctly assigns attributes to a model for each object found.
var foo = assetCollection.fetch({
reset: true,
success: function(response){
var data = response.models[0].attributes.collection.items;
data.forEach(function(data){
assetCollection.add([
{src_href: data.data[0].value,
title: data.data[1].value
}
]);
});
console.log(assetCollection.models)
}
})
Right now I am working with a static set of JSON that has two objects. However, logging assetCollection.models returns three objects: the first is the initial server JSON response, while the next two are correctly parsed Backbone models.
How do I keep Backbone from adding the first object (the entire response from the server) to its set of models, and instead just add the two JSON objects that I am interested in?
The JSON object returned from the server is as follows:
{
"collection": {
"version": "1.0",
"items": [
{
"href": "http://localhost:8080/api/assets/d7070f64-9899-4eca-8ba8-4f35184e0853",
"data": [
{
"name": "src_href",
"prompt": "Src_href",
"value": "http://cdn.images.express.co.uk/img/dynamic/36/590x/robin-williams-night-at-the-museum-498385.jpg"
},
{
"name": "title",
"prompt": "Title",
"value": "Robin as Teddy Roosevelt"
}
]
},
{
"href": "http://localhost:8080/api/assets/d7070f64-9899-4eca-8ba8-4f35184e0853",
"data": [
{
"name": "src_href",
"prompt": "Src_href",
"value": "http://b.vimeocdn.com/ts/164/830/164830426_640.jpg"
},
{
"name": "title",
"prompt": "Title",
"value": "Mrs. Doubtfire"
}
]
}
]
}
}
You should modufy collection.
Probably you should change parse method:
yourCollection = Backbone.Collection.extend({
parse: function(data) {
return data.models[0].attributes.collection.items;
}
})
When you use fetch Backbone parse result and add all elements what you return in parse.

Ember.js REST adapter handling different JSON structure

I'm using REST adapter, when I call App.Message.find() Ember.js makes call to the /messages to retrieve all messages and expect to see JSON structure like this:
{
"messages": [] // array contains objects
}
However API I have to work with response always with:
{
"data": [] // array contains objects
}
I only found the way1 to change namespace or URL for the API. How to tell REST adapter to look for data instead of messages property?
If this is not possible how to solve this problem? CTO said we can adapt API to use with REST adapter as we want, but from some reason we can't change this data property which will be on each response.
Assuming you are ok with writing your own adapter to deal with the difference, in the success callback you can simply modify the incoming name from "data" to your specific entity -in the case above "messages"
I do something like this to give you and idea of what if possible in a custom adapter
In the link below I highlighted the return line from my findMany
The json coming back from my REST api looks like
[
{
"id": 1,
"score": 2,
"feedback": "abc",
"session": 1
},
{
"id": 2,
"score": 4,
"feedback": "def",
"session": 1
}
]
I need to transform this before ember-data gets it to look like this
{
"sessions": [
{
"id": 1,
"score": 2,
"feedback": "abc",
"session": 1
},
{
"id": 2,
"score": 4,
"feedback": "def",
"session": 1
}
]
}
https://github.com/toranb/ember-data-django-rest-adapter/blob/master/packages/ember-data-django-rest-adapter/lib/adapter.js#L56-57
findMany: function(store, type, ids, parent) {
var json = {}
, adapter = this
, root = this.rootForType(type)
, plural = this.pluralize(root)
, ids = this.serializeIds(ids)
, url = this.buildFindManyUrlWithParent(store, type, ids, parent);
return this.ajax(url, "GET", {
data: {ids: ids}
}).then(function(pre_json) {
json[plural] = pre_json; //change the JSON before ember-data gets it
adapter.didFindMany(store, type, json);
}).then(null, rejectionHandler);
},

Categories

Resources