Constructing IRI from prefix and data in JSON-LD - json-ld

I have a problem to construct IRI for the object using a prefix and a data value when converting non-edited JSON data into JSON-LD. The example code I have running is:
{
"#context" :
{ "prefix" : "http://www.gerastree.at/",
"rdfs" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"#vocab" : "http://example.com/" ,
"load" : "prefix:load"
"items" : "prefix:item"
},
"#type" : "tree",
"#id" : "prefix:t1" ,
"items" :
[
{ "#id" : "prefix:t2",
"#type" : "item",
"load" : "some111"
},
{ "#id" : "prefix:t3",
"#type" : "item",
"load" : "some2222"
}
]
}
but when I change the #id values from "prefix:t1" to the plain data values I have in the original JSON (i.e. to just "t1", "t2" and "t3") the objects are not dealt with anymore.
The code which is not proper JSON-LD (at least not read by riot)
{
"#context" :
{ "prefix" : "http://www.gerastree.at/",
"rdfs" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"#vocab" : "http://example.com/" ,
"load" : "prefix:load"
"items" : "prefix:item"
},
"#type" : "tree",
"#id" : "t1" ,
"items" :
[
{ "#id" : "t2",
"#type" : "item",
"load" : "some111"
},
{ "#id" : "t3",
"#type" : "item",
"load" : "some2222"
}
]
}
The value "t1" etc. are unique and I would like to use them with a prefix as IRI to link the data with other data. Is there a way to produce the IRI with some addition to the context without changing the program which produces the JSON data or edit the file.
I found a solution (based on the solution of Json-LD > Define a "person" for easy reuse as values on different keys for WebPage schema) but do not understand why it works.
{
"#context" :
{ "prefix" : "http://www.gerastree.at/",
"rdfs" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"#base" : "http://example.com/" ,
"load" : "prefix:load",
"items" : "prefix:item"
},
"#type" : "tree",
"#id" : "t1" ,
"items" :
[
{ "#id" : "t2",
"#type" : "item",
"load" : "some111"
},
{ "#id" : "t3",
"#type" : "item",
"load" : "some2222"
}
]
}
I do not think this is a duplicate of Any way to specify the default URI for the #id of a #type or the values of a property? .
What additions and changes to the context are necesary?

I found the explanation why my third version works as desired with some more reading of the JSON-LD recommendations and experimentation.
#vocab is applied to properties and objects only
#base is used to complete IRI for the subject.
not really obvious but flexible enough for my application.

Related

MongoDB - Array element as variable

Lets say here is the same document:
{
"_id" : 1.0,
"custname" : "metlife",
"address" : {
"city" : "Bangalore",
"country" : "INDIA"
}
}
And if I want to push an extra field to this document, something like below:
db.customers.updateMany(
{"address.country":"INDIA"},
{$push : {city: "$address.country"}}
)
It results in wrong update:
{
"_id" : 1.0,
"custname" : "metlife",
"address" : {
"city" : "Bangalore",
"country" : "INDIA"
},
"city" : "$address.city"
}
Instead of this:
{
"_id" : 1.0,
"custname" : "metlife",
"address" : {
"city" : "Bangalore",
"country" : "INDIA"
},
"city" : "Bangalore"
}
How do I achieve the above result?
You can't refer to other field values in update currently (more here). There is a workaround in aggregation framework (using $out) but it will replace entire collection.
I think that you can consider using $rename in your case. It will not add new field but it can move city to the top level of your document.
db.customers.updateMany({"address.country":"INDIA"}, {$rename: {"address.city": "city"}})
will give you following structure:
{ "_id" : 1, "custname" : "metlife", "address" : { "country" : "INDIA" }, "city" : "Bangalore" }
like #mickl said : You can't refer to other field values in update currently,
you have to iterate through your collection to update the documents, try this :
db.eval(function() {
db.collection.find({"address.country":"INDIA"}).forEach(function(e) {
e.city= e.address.city;
db.collection.save(e);
});
});
Keep in mind that this will block the DB until all updates are done.
try this
db.customers.updateMany(
{"address.country":"INDIA"},
{$push : {city: "address.country"}}
)
remove $ sign

MongoDB - Pull multiple objects from an array

Hi I'm trying to remove multiple objects from an array that looks like this.
{
"_id" : ObjectId("5a7da1bda21d5f3e8cf005b3"),
"owner" : "1",
"group_name" : "PAASCU Board",
"group_members" : [
{
"faculty_name" : "Cheska Dela Rosa",
"faculty_number" : 2,
"_id" : ObjectId("5a7da1bda21d5f3e8cf005b5")
},
{
"faculty_name" : "Earl Sempio",
"faculty_number" : 7323,
"_id" : ObjectId("5a7da1bda21d5f3e8cf005b4")
},
{
"faculty_number" : 203,
"faculty_name" : "Sample",
"_id" : ObjectId("5a7dbf7952bd150a94d83958")
},
{
"faculty_number" : 8025,
"faculty_name" : "Sample Postman",
"_id" : ObjectId("5a7dc64a1cf5dd3d50167d53")
}
],
"__v" : 0 }
It works when I remove a single object using the $pull with this code.
db.getCollection('groups').update({_id: ObjectId("5a7da1bda21d5f3e8cf005b3")}, {$pull: {"group_members": {"faculty_number":8025}}})
But what if I want to remove multiple objects with different faculty_number? I tried using the $each method just like how I add multiple objects in the array but it doesn't work well.
Use $in operator to pass the list of faculty values to remove documents from embedded array. More here
Try
db.groups.update(
{"_id": ObjectId("5a7da1bda21d5f3e8cf005b3")},
{"$pull":{"group_members":{"faculty_number":{$in:[8025,7323]}}}}
)

mongodb - extract a particular value in an embedded array within an array

I'm fairly new to mongoDB, but I've managed to archive a load of documents into a new collection called documents_archived in the following format using an aggregation pipeleine:
{
"_id" : ObjectId("5a0046ef2039404645a42f52"),
"archive" : [
{
"_id" : ObjectId("54e60f49e4b097cc823afe8c"),
"_class" : "xxxxxxxxxxxxx",
"fields" : [
{
"key" : "Agreement Number",
"value" : "1002465507"
}
{
"key" : "Name",
"value" : "xxxxxxxx"
}
{
"key" : "Reg No",
"value" : "xxxxxxx"
}
{
"key" : "Surname",
"value" : "xxxxxxxx"
}
{
"key" : "Workflow Id",
"value" : "xxxxxxxx"
}
],
"fileName" : "Audit_C1002465507.txt",
"type" : "Workflow Audit",
"fileSize" : NumberLong(404),
"document" : BinData(0, "xxxxx"),
"creationDate" : ISODate("2009-09-25T00:00:00.000+0000"),
"lastModificationDate" : ISODate("2015-02-19T16:28:57.016+0000"),
"expiryDate" : ISODate("2018-09-25T00:00:00.000+0000")
}
]
}
Now, I'm trying to extract just the Agreement Number's value. However, I have tried many things that my limited knowledge, searching and documentation will allow. Wondered if the mongoDB experts out there can help. Thank you.
Here's a solution that uses the agg framework. I am assuming that each doc can have more than one entry in the archive field but only one Agreement Number in the fields array because your design appears to be key/value. If multiple Agreement Numbers show up in the fields array we'll have to add an additional $unwind but for the moment, this should work:
db.foo.aggregate([
{$unwind: "$archive"}
,{$project: {x: {$filter: {
input: "$archive.fields",
as: "z",
cond: {$eq: [ "$$z.key", "Agreement Number" ]}
}}
}}
,{$project: {_id:false, val: {$arrayElemAt: ["$x.value",0]} }}
]);
{ "val" : "1002465507" }
You can use following in mongo shell to extract only values:
db.documents_archived.find().forEach(function(doc) {
doc.archive[0].fields.forEach(function(field) {
if (field.key == "Agreement Number") {
print(field.value)
}
})
})

Searching JSON document in monogDB for value across array elements

I have some complex document (being new to mongodb schemas, I think it's complext) that I'm trying to process through for a specific array value match across different array sections of the document.
Sample content of my document:
{
"_id" : ObjectId("541c0c9bdfecb53368e12ef0"),
"SRVIP" : "10.10.10.10",
"INSNME" : "myinstance",
"DBNAME" : "mydbname",
"DBGRPL" : [{
"GRPNME" : "grp1",
"GRPPRV" : "7",
"GRPAUT" : [ “AUTH1”,”AUTH2”],
"GRPUSR" : [ "USER1",”USER2”]
}
],
"SAUTLV" : [ { "SAUNME" : "USER4",
"SAUPRV" : "0",
"SAUAUT" : [ “AUTH2”,”AUTH3”],
"SAUUSR" : [ "USER2" ]
}
],
"USRLVL" : [
{ "ULVNME" : "USER1",
"ULVPRV" : "0",
"ULVAUT" : [ "AUTH1","AUTH2","AUTH3"]
},
{
"ULVNME" : "USER2",
"ULVPRV" : "2411",
"ULVAUT" : [ "AUTH3"]
}
]
}
I'm trying to only return the section of the document where for example USER1 exists
At the moment, I've create two different aggregated statement to retrieve the information, but I'm looking at a single statement to search all arrays in the document.
Retrieving USER1 statement on DBGRPL array level :
var var1=[“USER1”]
db.authinfo.aggregate({$unwind:"$DBGRPL"},{$match:{"DBGRPL.GRPUSR":{$in:var1}}},{$project:{SRVIP:1,DBNAME:1,"DBGRPL":1}})
var var1=”USER1”
Retrieving USER1 statement on USRLVL array level:
db.authinfo.aggregate({$unwind:"$USRLVL"},{$match:{"USRLVL.ULVNME":var1}},{$project:{SRVIP:1,DBNAME:1,"USRLVL":1}})
The obvious error with the above approach is using 2 different variable type for the queries to work, which is also something I can't resolve at the moment ….
How can I combine the search into a single statement ?
expected output :
{
"_id" : ObjectId("541c0c9bdfecb53368e12ef0"),
"SRVIP" : "10.10.10.10",
"INSNME" : "myinstance",
"DBNAME" : "mydbname",
"DBGRPL" : [{
"GRPNME" : "grp1",
"GRPPRV" : "7",
"GRPAUT" : [ “AUTH1”,”AUTH2”],
"GRPUSR" : [ "USER1",”USER2”]
}
],
"USRLVL" : [
{ "ULVNME" : "USER1",
"ULVPRV" : "0",
"ULVAUT" : [ "AUTH1","AUTH2","AUTH3"]
}
{
]
}
when searching for USER1.
I will also search across the GRPAUTH, SAUAUT and ULVAUTH sections of the document where say AUTH1 is a value ...

Mongoose Query: Find an element inside an array

Mongoose/Mongo noob here:
My Data
Here is my simplified data, each user has his own document
{ "__v" : 1,
"_id" : ObjectId( "53440e94c02b3cae81eb0065" ),
"email" : "test#test.com",
"firstName" : "testFirstName",
"inventories" : [
{ "_id" : "active",
"tags" : [
"inventory",
"active",
"vehicles" ],
"title" : "activeInventory",
"vehicles" : [
{ "_id" : ObjectId( "53440e94c02b3cae81eb0069" ),
"tags" : [
"vehicle" ],
"details" : [
{ "_id" : ObjectId( "53440e94c02b3cae81eb0066" ),
"year" : 2007,
"transmission" : "Manual",
"price" : 1000,
"model" : "Firecar",
"mileageReading" : 50000,
"make" : "Bentley",
"interiorColor" : "blue",
"history" : "CarProof",
"exteriorColor" : "blue",
"driveTrain" : "SWD",
"description" : "test vehicle",
"cylinders" : 4,
"mileageType" : "kms" } ] } ] },
{ "title" : "soldInventory",
"_id" : "sold",
"vehicles" : [],
"tags" : [
"inventory",
"sold",
"vehicles" ] },
{ "title" : "deletedInventory",
"_id" : "deleted",
"vehicles" : [],
"tags" : [
"inventory",
"sold",
"vehicles" ] } ] }
As you can see, each user has an inventories property that is an array that contains 3 inventories (activeInventory, soldInventory and deletedInventory)
My Query
Given an user's email a a vehicle ID, i would like my query to go through find the user's activeInventory and return just the vehicle that matches the ID. Here is what I have so far:
user = api.mongodb.userModel;
ObjectId = require('mongoose').Types.ObjectId;
return user
.findOne({email : params.username})
.select('inventories')
.find({'title': 'activeInventory'})
//also tried
//.where('title')
//.equals('activeInventory')
.exec(function(err, result){
console.log(err);
console.log(result);
});
With this, result comes out as an empty array. I've also tried .find('inventories.title': 'activeInventory') which strangely returns the entire inventories array. If possible, I'd like to keep the chaining query format as I find it much more readable.
My Ideal Query
return user
.findOne({email : params.username})
.select('inventories')
.where('title')
.equals('activeInventory')
.select('vehicles')
.id(vehicleID)
.exec(cb)
Obviously it does not work but it can give you an idea what I'm trying to do.
Using the $ positional operator, you can get the results. However, if you have multiple elements in the vehicles array all of them will be returned in the result, as you can only use one positional operator in the projection and you are working with 2 arrays (one inside another).
I would suggest you take a look at the aggregation framework, as you'll get a lot more flexibility. Here's an example query for your question that runs in the shell. I'm not familiar with mongoose, but I guess this will still help you and you'd be able to translate it:
db.collection.aggregate([
// Get only the documents where "email" equals "test#test.com" -- REPLACE with params.username
{"$match" : {email : "test#test.com"}},
// Unwind the "inventories" array
{"$unwind" : "$inventories"},
// Get only elements where "inventories.title" equals "activeInventory"
{"$match" : {"inventories.title":"activeInventory"}},
// Unwind the "vehicles" array
{"$unwind" : "$inventories.vehicles"},
// Filter by vehicle ID -- REPLACE with vehicleID
{"$match" : {"inventories.vehicles._id":ObjectId("53440e94c02b3cae81eb0069")}},
// Tidy up the output
{"$project" : {_id:0, vehicle:"$inventories.vehicles"}}
])
This is the output you'll get:
{
"result" : [
{
"vehicle" : {
"_id" : ObjectId("53440e94c02b3cae81eb0069"),
"tags" : [
"vehicle"
],
"details" : [
{
"_id" : ObjectId("53440e94c02b3cae81eb0066"),
"year" : 2007,
"transmission" : "Manual",
"price" : 1000,
"model" : "Firecar",
"mileageReading" : 50000,
"make" : "Bentley",
"interiorColor" : "blue",
"history" : "CarProof",
"exteriorColor" : "blue",
"driveTrain" : "SWD",
"description" : "test vehicle",
"cylinders" : 4,
"mileageType" : "kms"
}
]
}
}
],
"ok" : 1
}
getting the chaining query format ... i dont know how to parse it but, what you are searching for is projection, you should take a look to http://docs.mongodb.org/manual/reference/operator/projection/
it would probably look like this :
user.findOne({email: params.username}, {'inventories.title': {$elemMatch: "activeInventory", 'invertories.vehicle.id': $elemMatch: params.vehicleId}, function(err, result) {
console.log(err);
console.log(result);
})

Resources