How to fetch nested values in MongoDB? - json

I have a 3 layer nested document something like this.
{
"_id" : ObjectId("5b5acaf0589ff6bfb5dd091f"),
"date" : "2018/07/31",
"clock" : [
{
"time" : "10:12:02",
"values" : [
{
"name" : "A1003",
"value" : "777"
},
{
"name" : "A0001",
"value" : "888"
}
]
},
{
"time" : "13:12:02",
"values" : [
{
"name" : "A1003",
"value" : "111"
}
]
}
]
}
I'm able to sort the date by using $gte $lte as below and all values are fetched.
getData(name: string[], fromDate: string, toDate: string): Promise<{ message: string }> {
return this._mongoUtility.testDb
.then(db => {
let collection = db.collection('TestDoc');
let fromOnlyDate = fromDate.split(' ');
let toOnlyDate = toDate.split(' ');
return collection.find({
'date': {
$gte: `${fromOnlyDate[0]}`,
$lte: `${toOnlyDate[1]}`
}
}).toArray();
})
.catch(err => {
return Promise.reject({message: 'Data not found', err: err})
})
}
I want to filter by using time and again by name and should display the value.
I tried in many ways but I'm getting the result. Is there nay other method to do so in MongoDB? Kindly suggest.
Expected output should look like below
0:{date: "2018/07/31 10:12:02", value-A1003: "777", value-A0001: "888"}
1:{date: "2018/07/31 13:12:02", value-A1003: "111"}

you can use the aggregate framwork to achive a simmler result(you cant create attr by value)
db.getCollection('sss').aggregate([
{$unwind:'$clock'},
{$unwind:'$clock.values'},
{$project:{
date: {$concat:[ "$date" ,' ' , "$clock.time" ]},
value:'$clock.values.value',
name:'$clock.values.name'
}}
])

Related

Angular json, filter unwanted json fields

I have an json from backend:
{
"_embedded" : {
"countries" : [ {
"id" : 1,
"name" : "Brazil",
"code" : "BR",
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/countries/1"
},
"country" : {
"href" : "http://localhost:8080/api/countries/1"
},
"states" : {
"href" : "http://localhost:8080/api/countries/1/states"
}
}
}, {
"id" : 2,
"name" : "Canada",
"code" : "CA",
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/countries/2"
},
"country" : {
"href" : "http://localhost:8080/api/countries/2"
},
"states" : {
"href" : "http://localhost:8080/api/countries/2/states"
}
}
}
}
}
And on frontend, I want to get data according to typescript interface:
interface Country {
id: number;
code: string;
name: string;
}
I have a code which maps above json to interface:
getCountries(): Observable<Country[]> {
return this.httpClient.get<CountriesResponse>(this.countriesUrl).pipe(
map(response => <Country[]>response._embedded.countries)
)
}
interface CountriesResponse {
_embedded: {
countries: Country[]
}
}
But after mapping method still returns data which is not present in typescript interface Country, I mean _links field.
Please suggest how to avoid it.
I actually found some solution but still thinks it could be done better:
getCountries(): Observable<Country[]> {
return this.httpClient.get<CountriesResponse>(this.countriesUrl).pipe(
map(response => {
const data: Country[] = response._embedded.countries
return data.map(c => ({
id: c.id,
name: c.name,
code: c.code
}))
})
)
}

Retrieve data from JSON file by ID in Angular. TypeError: items.find is not a function

Trying to get data by id from JSON file, but gives the error in console
TypeError: items.find is not a function
{
"product" :{
"data" : [
{ "itemID" : "1" , "name" : "pen" , "qty" : "8" }`,
{ "itemID" : "2" , "name" : "notepad" , "qty" : "5" }
]
} }
Function I am using where TypeError: items.find is not a function in console
getitems(itemID: string) {
return this.http.get<Array<Fruits>>('assets/localjson.json')
.pipe(
map((items: Array<any>) => {
return items.find((item: Fruits) => {
return item.itemID=== itemID;
});
})
);
}
office.ts
export class officeitems {
itemID: string;
name: string;
qty: string;
}
You need to use your structure correctly. Your structure is an object and you have treated it as an array.
So, you need to get your data from the product attribute because data is your array.
You need to change your getItems method and fix the interface defined.
map((product: any) => { // <- you need to use your interface Product { } instead of any
return product.data.find((item: Fruits) => {
return item.itemID=== itemID;
});
{
"product" :{
"data" : [
{ "itemID" : "1" , "name" : "pen" , "qty" : "8" }`,
{ "itemID" : "2" , "name" : "notepad" , "qty" : "5" }
]
}
}

How to access nested data in json string in typescript

I have this json structure an can't find a way to access the data values(data1, data2 and date), i'd like to have those values in an array than i can sort by date:
{
"07" : {
"07" : {
"data1" : "-1",
"data2" : "test",
"date" : "1995-07-07"
},
"08" : {
"data1" : "1",
"data2" : "test",
"date" : "1995-07-08"
},
"09" : {
"data1" : "-1",
"data2" : "test",
"date" : "1995-07-09"
},
"10" : {
"data1" : "-1",
"data2" : "test",
"date" : "1995-07-10"
}
},
"08" : {
"07" : {
"data1" : "1",
"data2" : "test",
"date" : "1995-08-07"
},
"08" : {
"data1" : "1",
"data2" : "test",
"date" : "1995-08-08"
},
"09" : {
"data1" : "1",
"data2" : "test",
"date" : "1995-08-09"
}
}
}
Because my keys aren't defined as constant i don't know what they'll be in advance.
Polyfill for Object.entries:
const reduce = Function.bind.call(Function.call, Array.prototype.reduce);
const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable);
const concat = Function.bind.call(Function.call, Array.prototype.concat);
const keys = Reflect.ownKeys;
if (!Object.values) {
Object.values = function values(O) {
return reduce(keys(O), (v, k) => concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : []), []);
};
}
if (!Object.entries) {
Object.entries = function entries(O) {
return reduce(keys(O), (e, k) => concat(e, typeof k === 'string' && isEnumerable(O, k) ? [[k, O[k]]] : []), []);
};
}
Code:
for (const [key, value] of Object.entries(myObject))
{
for (const [key2, value2] of Object.entries(value))
{
value2.data1;
value2.data2;
value2.date;
}
}
Instead Object.entries you can enumerate object like this.
for (var key in myObject)
{
for (var key2 in myObject[key])
{
myObject[key][key2].data1;
myObject[key][key2].data2;
myObject[key][key2].date;
}
}
You can get all the key names from your json as an Array by calling the method:
keys = Object.getOwnPropertyNames(jsonObj);
In your example this will return an array ['07', '08'] to get the actual objects from the name you can call:
keys.forEach((key) => {
objects = Object.getOwnPropertyDescriptor(jsonObj, key)
})
And then you can find the names of the keys of these objects and repeat
objects.forEach((object) => {
keys = Object.getOwnPropertyNames(object);
})

saving in the database variable as ObjectID() MongoDB, NodeJS

I created function which is adding people_id inside array of given card. But there is problem that inserted id is always not as an objectId() where I just need it to be saved as objectId.
When id is added to array i I'm sending whole variable board JSON to nodejs API where is executed function findOneAndUpdate. And here is problem because after saved this arrays is not objectID in Author. Can someone tell me how to make it?
JSON board
{
"_id" : ObjectId("59e096a7622a3825ac24f343"),
"name" : "1",
"users" : [
ObjectId("59cd114cea98d9326ca1c421")
],
"lists" : [
{
"list" : "1",
"cards" : [
{
"name" : "2",
"Author" : [
"59df60fb6fad6224f4f9f22d",
"59df60fb6fad6224f4f9f22d",
"59df60fb6fad6224f4f9f22e"
]
},
{
"name" : "3",
"Author" : []
}
]
},
{
"list" : "fea",
"cards" : [
{
"name" : "card",
"Author" : []
}
]
}
],
"__v" : 0 }
Router:
router.post('/add/member', function (req, res, next) {
console.log(req.body)
Board.findOneAndUpdate({ _id: req.body._id },
{
$set: {
lists : req.body.lists
}
},
{
upsert: true
},
((cards) => {
res.send(cards)
})
)
});
model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var BoardSchema = new Schema({
name: { type: String, maxlength: 20 },
lists : { type: Array },
users : [{ type : Schema.Types.ObjectId, ref: 'User' }],
});
module.exports = mongoose.model('Board', BoardSchema);
And here is function with adding poeple
$scope.addMemberToCard = (indexList, indexCard, member) => {
$scope.board.lists[indexList].cards[indexCard].Author.push(member);
console.log( $scope.board.lists[indexList].cards[indexCard].Author)
return ApiService.staff.addMemberToCard($scope.board).then(function () {
})
}
You could use the mongoose Types ObjectID method and then transform the string sent into an ObjectID.
const id = new new mongoose.Types.ObjectId(Author);

Query to return a field from a nested json using MongoDB

My database has data in the following format :
{ "_id" : ObjectId( "abcd" ),
"coordinate" : [somevalue, somevalue],
"value" : [
{ "time" : 1,
"characteristics" : "pqrs" },
{ "time" : 10,
"characteristics" : "pqrs" } ] }
I want to find the field closest coordinate and a time that is less than or equal to a given value.
Currently I'm using this query :
db.collection.aggregate({
coordinate: {
$geoNear: [latitude, longitude],
$maxDistance: 10
},
"value.time": {
$lte: 5
}
})
This one returned the entire entry, but what I wanted is the field:
{ "time" : 1, "characteristics" : "pqrs" }
Is it even possible to just return this field ? What if there are multiple result and I just want the one that's closest to my value.time input ?
You can perform an aggregation to :
$match items with specified coordinate and value.time
$filter value array to remove everything < 5
$unwind value array
$group by max value
Query is :
db.collection.aggregate({
$match: {
coordinate: {
$geoNear: [0, 0],
$maxDistance: 10
},
"value.time": {
$lte: 5
}
}
}, {
$project: {
value: {
$filter: {
input: "$value",
as: "value",
cond: { $lte: ["$$value.time", 5] }
}
}
}
}, {
$unwind: "$value"
}, {
$group: {
_id: "$_id",
time: { $max: "$value.time" },
characteristics: { $first: "$value.characteristics" }
}
})
Sample output :
{ "_id" : ObjectId("588a8c3080a14de2d654eb7b"), "time" : 4, "characteristics" : "pqrs" }
{ "_id" : ObjectId("588a89327fe89686fd2210b2"), "time" : 1, "characteristics" : "pqrs" }